xref: /onnv-gate/usr/src/common/openssl/crypto/engine/README (revision 0:68f95e015346)
1*0Sstevel@tonic-gateNotes: 2001-09-24
2*0Sstevel@tonic-gate-----------------
3*0Sstevel@tonic-gate
4*0Sstevel@tonic-gateThis "description" (if one chooses to call it that) needed some major updating
5*0Sstevel@tonic-gateso here goes. This update addresses a change being made at the same time to
6*0Sstevel@tonic-gateOpenSSL, and it pretty much completely restructures the underlying mechanics of
7*0Sstevel@tonic-gatethe "ENGINE" code. So it serves a double purpose of being a "ENGINE internals
8*0Sstevel@tonic-gatefor masochists" document *and* a rather extensive commit log message. (I'd get
9*0Sstevel@tonic-gatelynched for sticking all this in CHANGES or the commit mails :-).
10*0Sstevel@tonic-gate
11*0Sstevel@tonic-gateENGINE_TABLE underlies this restructuring, as described in the internal header
12*0Sstevel@tonic-gate"eng_int.h", implemented in eng_table.c, and used in each of the "class" files;
13*0Sstevel@tonic-gatetb_rsa.c, tb_dsa.c, etc.
14*0Sstevel@tonic-gate
15*0Sstevel@tonic-gateHowever, "EVP_CIPHER" underlies the motivation and design of ENGINE_TABLE so
16*0Sstevel@tonic-gateI'll mention a bit about that first. EVP_CIPHER (and most of this applies
17*0Sstevel@tonic-gateequally to EVP_MD for digests) is both a "method" and a algorithm/mode
18*0Sstevel@tonic-gateidentifier that, in the current API, "lingers". These cipher description +
19*0Sstevel@tonic-gateimplementation structures can be defined or obtained directly by applications,
20*0Sstevel@tonic-gateor can be loaded "en masse" into EVP storage so that they can be catalogued and
21*0Sstevel@tonic-gatesearched in various ways, ie. two ways of encrypting with the "des_cbc"
22*0Sstevel@tonic-gatealgorithm/mode pair are;
23*0Sstevel@tonic-gate
24*0Sstevel@tonic-gate(i) directly;
25*0Sstevel@tonic-gate     const EVP_CIPHER *cipher = EVP_des_cbc();
26*0Sstevel@tonic-gate     EVP_EncryptInit(&ctx, cipher, key, iv);
27*0Sstevel@tonic-gate     [ ... use EVP_EncryptUpdate() and EVP_EncryptFinal() ...]
28*0Sstevel@tonic-gate
29*0Sstevel@tonic-gate(ii) indirectly;
30*0Sstevel@tonic-gate     OpenSSL_add_all_ciphers();
31*0Sstevel@tonic-gate     cipher = EVP_get_cipherbyname("des_cbc");
32*0Sstevel@tonic-gate     EVP_EncryptInit(&ctx, cipher, key, iv);
33*0Sstevel@tonic-gate     [ ... etc ... ]
34*0Sstevel@tonic-gate
35*0Sstevel@tonic-gateThe latter is more generally used because it also allows ciphers/digests to be
36*0Sstevel@tonic-gatelooked up based on other identifiers which can be useful for automatic cipher
37*0Sstevel@tonic-gateselection, eg. in SSL/TLS, or by user-controllable configuration.
38*0Sstevel@tonic-gate
39*0Sstevel@tonic-gateThe important point about this is that EVP_CIPHER definitions and structures are
40*0Sstevel@tonic-gatepassed around with impunity and there is no safe way, without requiring massive
41*0Sstevel@tonic-gaterewrites of many applications, to assume that EVP_CIPHERs can be reference
42*0Sstevel@tonic-gatecounted. One an EVP_CIPHER is exposed to the caller, neither it nor anything it
43*0Sstevel@tonic-gatecomes from can "safely" be destroyed. Unless of course the way of getting to
44*0Sstevel@tonic-gatesuch ciphers is via entirely distinct API calls that didn't exist before.
45*0Sstevel@tonic-gateHowever existing API usage cannot be made to understand when an EVP_CIPHER
46*0Sstevel@tonic-gatepointer, that has been passed to the caller, is no longer being used.
47*0Sstevel@tonic-gate
48*0Sstevel@tonic-gateThe other problem with the existing API w.r.t. to hooking EVP_CIPHER support
49*0Sstevel@tonic-gateinto ENGINE is storage - the OBJ_NAME-based storage used by EVP to register
50*0Sstevel@tonic-gateciphers simultaneously registers cipher *types* and cipher *implementations* -
51*0Sstevel@tonic-gatethey are effectively the same thing, an "EVP_CIPHER" pointer. The problem with
52*0Sstevel@tonic-gatehooking in ENGINEs is that multiple ENGINEs may implement the same ciphers. The
53*0Sstevel@tonic-gatesolution is necessarily that ENGINE-provided ciphers simply are not registered,
54*0Sstevel@tonic-gatestored, or exposed to the caller in the same manner as existing ciphers. This is
55*0Sstevel@tonic-gateespecially necessary considering the fact ENGINE uses reference counts to allow
56*0Sstevel@tonic-gatefor cleanup, modularity, and DSO support - yet EVP_CIPHERs, as exposed to
57*0Sstevel@tonic-gatecallers in the current API, support no such controls.
58*0Sstevel@tonic-gate
59*0Sstevel@tonic-gateAnother sticking point for integrating cipher support into ENGINE is linkage.
60*0Sstevel@tonic-gateAlready there is a problem with the way ENGINE supports RSA, DSA, etc whereby
61*0Sstevel@tonic-gatethey are available *because* they're part of a giant ENGINE called "openssl".
62*0Sstevel@tonic-gateIe. all implementations *have* to come from an ENGINE, but we get round that by
63*0Sstevel@tonic-gatehaving a giant ENGINE with all the software support encapsulated. This creates
64*0Sstevel@tonic-gatelinker hassles if nothing else - linking a 1-line application that calls 2 basic
65*0Sstevel@tonic-gateRSA functions (eg. "RSA_free(RSA_new());") will result in large quantities of
66*0Sstevel@tonic-gateENGINE code being linked in *and* because of that DSA, DH, and RAND also. If we
67*0Sstevel@tonic-gatecontinue with this approach for EVP_CIPHER support (even if it *was* possible)
68*0Sstevel@tonic-gatewe would lose our ability to link selectively by selectively loading certain
69*0Sstevel@tonic-gateimplementations of certain functionality. Touching any part of any kind of
70*0Sstevel@tonic-gatecrypto would result in massive static linkage of everything else. So the
71*0Sstevel@tonic-gatesolution is to change the way ENGINE feeds existing "classes", ie. how the
72*0Sstevel@tonic-gatehooking to ENGINE works from RSA, DSA, DH, RAND, as well as adding new hooking
73*0Sstevel@tonic-gatefor EVP_CIPHER, and EVP_MD.
74*0Sstevel@tonic-gate
75*0Sstevel@tonic-gateThe way this is now being done is by mostly reverting back to how things used to
76*0Sstevel@tonic-gatework prior to ENGINE :-). Ie. RSA now has a "RSA_METHOD" pointer again - this
77*0Sstevel@tonic-gatewas previously replaced by an "ENGINE" pointer and all RSA code that required
78*0Sstevel@tonic-gatethe RSA_METHOD would call ENGINE_get_RSA() each time on its ENGINE handle to
79*0Sstevel@tonic-gatetemporarily get and use the ENGINE's RSA implementation. Apart from being more
80*0Sstevel@tonic-gateefficient, switching back to each RSA having an RSA_METHOD pointer also allows
81*0Sstevel@tonic-gateus to conceivably operate with *no* ENGINE. As we'll see, this removes any need
82*0Sstevel@tonic-gatefor a fallback ENGINE that encapsulates default implementations - we can simply
83*0Sstevel@tonic-gatehave our RSA structure pointing its RSA_METHOD pointer to the software
84*0Sstevel@tonic-gateimplementation and have its ENGINE pointer set to NULL.
85*0Sstevel@tonic-gate
86*0Sstevel@tonic-gateA look at the EVP_CIPHER hooking is most explanatory, the RSA, DSA (etc) cases
87*0Sstevel@tonic-gateturn out to be degenerate forms of the same thing. The EVP storage of ciphers,
88*0Sstevel@tonic-gateand the existing EVP API functions that return "software" implementations and
89*0Sstevel@tonic-gatedescriptions remain untouched. However, the storage takes more meaning in terms
90*0Sstevel@tonic-gateof "cipher description" and less meaning in terms of "implementation". When an
91*0Sstevel@tonic-gateEVP_CIPHER_CTX is actually initialised with an EVP_CIPHER method and is about to
92*0Sstevel@tonic-gatebegin en/decryption, the hooking to ENGINE comes into play. What happens is that
93*0Sstevel@tonic-gatecipher-specific ENGINE code is asked for an ENGINE pointer (a functional
94*0Sstevel@tonic-gatereference) for any ENGINE that is registered to perform the algo/mode that the
95*0Sstevel@tonic-gateprovided EVP_CIPHER structure represents. Under normal circumstances, that
96*0Sstevel@tonic-gateENGINE code will return NULL because no ENGINEs will have had any cipher
97*0Sstevel@tonic-gateimplementations *registered*. As such, a NULL ENGINE pointer is stored in the
98*0Sstevel@tonic-gateEVP_CIPHER_CTX context, and the EVP_CIPHER structure is left hooked into the
99*0Sstevel@tonic-gatecontext and so is used as the implementation. Pretty much how things work now
100*0Sstevel@tonic-gateexcept we'd have a redundant ENGINE pointer set to NULL and doing nothing.
101*0Sstevel@tonic-gate
102*0Sstevel@tonic-gateConversely, if an ENGINE *has* been registered to perform the algorithm/mode
103*0Sstevel@tonic-gatecombination represented by the provided EVP_CIPHER, then a functional reference
104*0Sstevel@tonic-gateto that ENGINE will be returned to the EVP_CIPHER_CTX during initialisation.
105*0Sstevel@tonic-gateThat functional reference will be stored in the context (and released on
106*0Sstevel@tonic-gatecleanup) - and having that reference provides a *safe* way to use an EVP_CIPHER
107*0Sstevel@tonic-gatedefinition that is private to the ENGINE. Ie. the EVP_CIPHER provided by the
108*0Sstevel@tonic-gateapplication will actually be replaced by an EVP_CIPHER from the registered
109*0Sstevel@tonic-gateENGINE - it will support the same algorithm/mode as the original but will be a
110*0Sstevel@tonic-gatecompletely different implementation. Because this EVP_CIPHER isn't stored in the
111*0Sstevel@tonic-gateEVP storage, nor is it returned to applications from traditional API functions,
112*0Sstevel@tonic-gatethere is no associated problem with it not having reference counts. And of
113*0Sstevel@tonic-gatecourse, when one of these "private" cipher implementations is hooked into
114*0Sstevel@tonic-gateEVP_CIPHER_CTX, it is done whilst the EVP_CIPHER_CTX holds a functional
115*0Sstevel@tonic-gatereference to the ENGINE that owns it, thus the use of the ENGINE's EVP_CIPHER is
116*0Sstevel@tonic-gatesafe.
117*0Sstevel@tonic-gate
118*0Sstevel@tonic-gateThe "cipher-specific ENGINE code" I mentioned is implemented in tb_cipher.c but
119*0Sstevel@tonic-gatein essence it is simply an instantiation of "ENGINE_TABLE" code for use by
120*0Sstevel@tonic-gateEVP_CIPHER code. tb_digest.c is virtually identical but, of course, it is for
121*0Sstevel@tonic-gateuse by EVP_MD code. Ditto for tb_rsa.c, tb_dsa.c, etc. These instantiations of
122*0Sstevel@tonic-gateENGINE_TABLE essentially provide linker-separation of the classes so that even
123*0Sstevel@tonic-gateif ENGINEs implement *all* possible algorithms, an application using only
124*0Sstevel@tonic-gateEVP_CIPHER code will link at most code relating to EVP_CIPHER, tb_cipher.c, core
125*0Sstevel@tonic-gateENGINE code that is independant of class, and of course the ENGINE
126*0Sstevel@tonic-gateimplementation that the application loaded. It will *not* however link any
127*0Sstevel@tonic-gateclass-specific ENGINE code for digests, RSA, etc nor will it bleed over into
128*0Sstevel@tonic-gateother APIs, such as the RSA/DSA/etc library code.
129*0Sstevel@tonic-gate
130*0Sstevel@tonic-gateENGINE_TABLE is a little more complicated than may seem necessary but this is
131*0Sstevel@tonic-gatemostly to avoid a lot of "init()"-thrashing on ENGINEs (that may have to load
132*0Sstevel@tonic-gateDSOs, and other expensive setup that shouldn't be thrashed unnecessarily) *and*
133*0Sstevel@tonic-gateto duplicate "default" behaviour. Basically an ENGINE_TABLE instantiation, for
134*0Sstevel@tonic-gateexample tb_cipher.c, implements a hash-table keyed by integer "nid" values.
135*0Sstevel@tonic-gateThese nids provide the uniquenness of an algorithm/mode - and each nid will hash
136*0Sstevel@tonic-gateto a potentially NULL "ENGINE_PILE". An ENGINE_PILE is essentially a list of
137*0Sstevel@tonic-gatepointers to ENGINEs that implement that particular 'nid'. Each "pile" uses some
138*0Sstevel@tonic-gatecaching tricks such that requests on that 'nid' will be cached and all future
139*0Sstevel@tonic-gaterequests will return immediately (well, at least with minimal operation) unless
140*0Sstevel@tonic-gatea change is made to the pile, eg. perhaps an ENGINE was unloaded. The reason is
141*0Sstevel@tonic-gatethat an application could have support for 10 ENGINEs statically linked
142*0Sstevel@tonic-gatein, and the machine in question may not have any of the hardware those 10
143*0Sstevel@tonic-gateENGINEs support. If each of those ENGINEs has a "des_cbc" implementation, we
144*0Sstevel@tonic-gatewant to avoid every EVP_CIPHER_CTX setup from trying (and failing) to initialise
145*0Sstevel@tonic-gateeach of those 10 ENGINEs. Instead, the first such request will try to do that
146*0Sstevel@tonic-gateand will either return (and cache) a NULL ENGINE pointer or will return a
147*0Sstevel@tonic-gatefunctional reference to the first that successfully initialised. In the latter
148*0Sstevel@tonic-gatecase it will also cache an extra functional reference to the ENGINE as a
149*0Sstevel@tonic-gate"default" for that 'nid'. The caching is acknowledged by a 'uptodate' variable
150*0Sstevel@tonic-gatethat is unset only if un/registration takes place on that pile. Ie. if
151*0Sstevel@tonic-gateimplementations of "des_cbc" are added or removed. This behaviour can be
152*0Sstevel@tonic-gatetweaked; the ENGINE_TABLE_FLAG_NOINIT value can be passed to
153*0Sstevel@tonic-gateENGINE_set_table_flags(), in which case the only ENGINEs that tb_cipher.c will
154*0Sstevel@tonic-gatetry to initialise from the "pile" will be those that are already initialised
155*0Sstevel@tonic-gate(ie. it's simply an increment of the functional reference count, and no real
156*0Sstevel@tonic-gate"initialisation" will take place).
157*0Sstevel@tonic-gate
158*0Sstevel@tonic-gateRSA, DSA, DH, and RAND all have their own ENGINE_TABLE code as well, and the
159*0Sstevel@tonic-gatedifference is that they all use an implicit 'nid' of 1. Whereas EVP_CIPHERs are
160*0Sstevel@tonic-gateactually qualitatively different depending on 'nid' (the "des_cbc" EVP_CIPHER is
161*0Sstevel@tonic-gatenot an interoperable implementation of "aes_256_cbc"), RSA_METHODs are
162*0Sstevel@tonic-gatenecessarily interoperable and don't have different flavours, only different
163*0Sstevel@tonic-gateimplementations. In other words, the ENGINE_TABLE for RSA will either be empty,
164*0Sstevel@tonic-gateor will have a single ENGING_PILE hashed to by the 'nid' 1 and that pile
165*0Sstevel@tonic-gaterepresents ENGINEs that implement the single "type" of RSA there is.
166*0Sstevel@tonic-gate
167*0Sstevel@tonic-gateCleanup - the registration and unregistration may pose questions about how
168*0Sstevel@tonic-gatecleanup works with the ENGINE_PILE doing all this caching nonsense (ie. when the
169*0Sstevel@tonic-gateapplication or EVP_CIPHER code releases its last reference to an ENGINE, the
170*0Sstevel@tonic-gateENGINE_PILE code may still have references and thus those ENGINEs will stay
171*0Sstevel@tonic-gatehooked in forever). The way this is handled is via "unregistration". With these
172*0Sstevel@tonic-gatenew ENGINE changes, an abstract ENGINE can be loaded and initialised, but that
173*0Sstevel@tonic-gateis an algorithm-agnostic process. Even if initialised, it will not have
174*0Sstevel@tonic-gateregistered any of its implementations (to do so would link all class "table"
175*0Sstevel@tonic-gatecode despite the fact the application may use only ciphers, for example). This
176*0Sstevel@tonic-gateis deliberately a distinct step. Moreover, registration and unregistration has
177*0Sstevel@tonic-gatenothing to do with whether an ENGINE is *functional* or not (ie. you can even
178*0Sstevel@tonic-gateregister an ENGINE and its implementations without it being operational, you may
179*0Sstevel@tonic-gatenot even have the drivers to make it operate). What actually happens with
180*0Sstevel@tonic-gaterespect to cleanup is managed inside eng_lib.c with the "engine_cleanup_***"
181*0Sstevel@tonic-gatefunctions. These functions are internal-only and each part of ENGINE code that
182*0Sstevel@tonic-gatecould require cleanup will, upon performing its first allocation, register a
183*0Sstevel@tonic-gatecallback with the "engine_cleanup" code. The other part of this that makes it
184*0Sstevel@tonic-gatetick is that the ENGINE_TABLE instantiations (tb_***.c) use NULL as their
185*0Sstevel@tonic-gateinitialised state. So if RSA code asks for an ENGINE and no ENGINE has
186*0Sstevel@tonic-gateregistered an implementation, the code will simply return NULL and the tb_rsa.c
187*0Sstevel@tonic-gatestate will be unchanged. Thus, no cleanup is required unless registration takes
188*0Sstevel@tonic-gateplace. ENGINE_cleanup() will simply iterate across a list of registered cleanup
189*0Sstevel@tonic-gatecallbacks calling each in turn, and will then internally delete its own storage
190*0Sstevel@tonic-gate(a STACK). When a cleanup callback is next registered (eg. if the cleanup() is
191*0Sstevel@tonic-gatepart of a gracefull restart and the application wants to cleanup all state then
192*0Sstevel@tonic-gatestart again), the internal STACK storage will be freshly allocated. This is much
193*0Sstevel@tonic-gatethe same as the situation in the ENGINE_TABLE instantiations ... NULL is the
194*0Sstevel@tonic-gateinitialised state, so only modification operations (not queries) will cause that
195*0Sstevel@tonic-gatecode to have to register a cleanup.
196*0Sstevel@tonic-gate
197*0Sstevel@tonic-gateWhat else? The bignum callbacks and associated ENGINE functions have been
198*0Sstevel@tonic-gateremoved for two obvious reasons; (i) there was no way to generalise them to the
199*0Sstevel@tonic-gatemechanism now used by RSA/DSA/..., because there's no such thing as a BIGNUM
200*0Sstevel@tonic-gatemethod, and (ii) because of (i), there was no meaningful way for library or
201*0Sstevel@tonic-gateapplication code to automatically hook and use ENGINE supplied bignum functions
202*0Sstevel@tonic-gateanyway. Also, ENGINE_cpy() has been removed (although an internal-only version
203*0Sstevel@tonic-gateexists) - the idea of providing an ENGINE_cpy() function probably wasn't a good
204*0Sstevel@tonic-gateone and now certainly doesn't make sense in any generalised way. Some of the
205*0Sstevel@tonic-gateRSA, DSA, DH, and RAND functions that were fiddled during the original ENGINE
206*0Sstevel@tonic-gatechanges have now, as a consequence, been reverted back. This is because the
207*0Sstevel@tonic-gatehooking of ENGINE is now automatic (and passive, it can interally use a NULL
208*0Sstevel@tonic-gateENGINE pointer to simply ignore ENGINE from then on).
209*0Sstevel@tonic-gate
210*0Sstevel@tonic-gateHell, that should be enough for now ... comments welcome: geoff@openssl.org
211*0Sstevel@tonic-gate
212