1 | =pod
|
---|
2 |
|
---|
3 | =head1 NAME
|
---|
4 |
|
---|
5 | provider-base
|
---|
6 | - The basic OpenSSL library E<lt>-E<gt> provider functions
|
---|
7 |
|
---|
8 | =head1 SYNOPSIS
|
---|
9 |
|
---|
10 | #include <openssl/core_dispatch.h>
|
---|
11 |
|
---|
12 | /*
|
---|
13 | * None of these are actual functions, but are displayed like this for
|
---|
14 | * the function signatures for functions that are offered as function
|
---|
15 | * pointers in OSSL_DISPATCH arrays.
|
---|
16 | */
|
---|
17 |
|
---|
18 | /* Functions offered by libcrypto to the providers */
|
---|
19 | const OSSL_ITEM *core_gettable_params(const OSSL_CORE_HANDLE *handle);
|
---|
20 | int core_get_params(const OSSL_CORE_HANDLE *handle, OSSL_PARAM params[]);
|
---|
21 |
|
---|
22 | typedef void (*OSSL_thread_stop_handler_fn)(void *arg);
|
---|
23 | int core_thread_start(const OSSL_CORE_HANDLE *handle,
|
---|
24 | OSSL_thread_stop_handler_fn handfn,
|
---|
25 | void *arg);
|
---|
26 |
|
---|
27 | OPENSSL_CORE_CTX *core_get_libctx(const OSSL_CORE_HANDLE *handle);
|
---|
28 | void core_new_error(const OSSL_CORE_HANDLE *handle);
|
---|
29 | void core_set_error_debug(const OSSL_CORE_HANDLE *handle,
|
---|
30 | const char *file, int line, const char *func);
|
---|
31 | void core_vset_error(const OSSL_CORE_HANDLE *handle,
|
---|
32 | uint32_t reason, const char *fmt, va_list args);
|
---|
33 |
|
---|
34 | int core_obj_add_sigid(const OSSL_CORE_HANDLE *prov, const char *sign_name,
|
---|
35 | const char *digest_name, const char *pkey_name);
|
---|
36 | int core_obj_create(const OSSL_CORE_HANDLE *handle, const char *oid,
|
---|
37 | const char *sn, const char *ln);
|
---|
38 |
|
---|
39 | /*
|
---|
40 | * Some OpenSSL functionality is directly offered to providers via
|
---|
41 | * dispatch
|
---|
42 | */
|
---|
43 | void *CRYPTO_malloc(size_t num, const char *file, int line);
|
---|
44 | void *CRYPTO_zalloc(size_t num, const char *file, int line);
|
---|
45 | void CRYPTO_free(void *ptr, const char *file, int line);
|
---|
46 | void CRYPTO_clear_free(void *ptr, size_t num,
|
---|
47 | const char *file, int line);
|
---|
48 | void *CRYPTO_realloc(void *addr, size_t num,
|
---|
49 | const char *file, int line);
|
---|
50 | void *CRYPTO_clear_realloc(void *addr, size_t old_num, size_t num,
|
---|
51 | const char *file, int line);
|
---|
52 | void *CRYPTO_secure_malloc(size_t num, const char *file, int line);
|
---|
53 | void *CRYPTO_secure_zalloc(size_t num, const char *file, int line);
|
---|
54 | void CRYPTO_secure_free(void *ptr, const char *file, int line);
|
---|
55 | void CRYPTO_secure_clear_free(void *ptr, size_t num,
|
---|
56 | const char *file, int line);
|
---|
57 | int CRYPTO_secure_allocated(const void *ptr);
|
---|
58 | void OPENSSL_cleanse(void *ptr, size_t len);
|
---|
59 |
|
---|
60 | unsigned char *OPENSSL_hexstr2buf(const char *str, long *buflen);
|
---|
61 |
|
---|
62 | OSSL_CORE_BIO *BIO_new_file(const char *filename, const char *mode);
|
---|
63 | OSSL_CORE_BIO *BIO_new_membuf(const void *buf, int len);
|
---|
64 | int BIO_read_ex(OSSL_CORE_BIO *bio, void *data, size_t data_len,
|
---|
65 | size_t *bytes_read);
|
---|
66 | int BIO_write_ex(OSSL_CORE_BIO *bio, const void *data, size_t data_len,
|
---|
67 | size_t *written);
|
---|
68 | int BIO_up_ref(OSSL_CORE_BIO *bio);
|
---|
69 | int BIO_free(OSSL_CORE_BIO *bio);
|
---|
70 | int BIO_vprintf(OSSL_CORE_BIO *bio, const char *format, va_list args);
|
---|
71 | int BIO_vsnprintf(char *buf, size_t n, const char *fmt, va_list args);
|
---|
72 |
|
---|
73 | void OSSL_SELF_TEST_set_callback(OSSL_LIB_CTX *libctx, OSSL_CALLBACK *cb,
|
---|
74 | void *cbarg);
|
---|
75 |
|
---|
76 | size_t get_entropy(const OSSL_CORE_HANDLE *handle,
|
---|
77 | unsigned char **pout, int entropy,
|
---|
78 | size_t min_len, size_t max_len);
|
---|
79 | void cleanup_entropy(const OSSL_CORE_HANDLE *handle,
|
---|
80 | unsigned char *buf, size_t len);
|
---|
81 | size_t get_nonce(const OSSL_CORE_HANDLE *handle,
|
---|
82 | unsigned char **pout, size_t min_len, size_t max_len,
|
---|
83 | const void *salt, size_t salt_len);
|
---|
84 | void cleanup_nonce(const OSSL_CORE_HANDLE *handle,
|
---|
85 | unsigned char *buf, size_t len);
|
---|
86 |
|
---|
87 | /* Functions for querying the providers in the application library context */
|
---|
88 | int provider_register_child_cb(const OSSL_CORE_HANDLE *handle,
|
---|
89 | int (*create_cb)(const OSSL_CORE_HANDLE *provider,
|
---|
90 | void *cbdata),
|
---|
91 | int (*remove_cb)(const OSSL_CORE_HANDLE *provider,
|
---|
92 | void *cbdata),
|
---|
93 | int (*global_props_cb)(const char *props, void *cbdata),
|
---|
94 | void *cbdata);
|
---|
95 | void provider_deregister_child_cb(const OSSL_CORE_HANDLE *handle);
|
---|
96 | const char *provider_name(const OSSL_CORE_HANDLE *prov);
|
---|
97 | void *provider_get0_provider_ctx(const OSSL_CORE_HANDLE *prov);
|
---|
98 | const OSSL_DISPATCH *provider_get0_dispatch(const OSSL_CORE_HANDLE *prov);
|
---|
99 | int provider_up_ref(const OSSL_CORE_HANDLE *prov, int activate);
|
---|
100 | int provider_free(const OSSL_CORE_HANDLE *prov, int deactivate);
|
---|
101 |
|
---|
102 | /* Functions offered by the provider to libcrypto */
|
---|
103 | void provider_teardown(void *provctx);
|
---|
104 | const OSSL_ITEM *provider_gettable_params(void *provctx);
|
---|
105 | int provider_get_params(void *provctx, OSSL_PARAM params[]);
|
---|
106 | const OSSL_ALGORITHM *provider_query_operation(void *provctx,
|
---|
107 | int operation_id,
|
---|
108 | const int *no_store);
|
---|
109 | void provider_unquery_operation(void *provctx, int operation_id,
|
---|
110 | const OSSL_ALGORITHM *algs);
|
---|
111 | const OSSL_ITEM *provider_get_reason_strings(void *provctx);
|
---|
112 | int provider_get_capabilities(void *provctx, const char *capability,
|
---|
113 | OSSL_CALLBACK *cb, void *arg);
|
---|
114 | int provider_self_test(void *provctx);
|
---|
115 |
|
---|
116 | =head1 DESCRIPTION
|
---|
117 |
|
---|
118 | All "functions" mentioned here are passed as function pointers between
|
---|
119 | F<libcrypto> and the provider in B<OSSL_DISPATCH> arrays, in the call
|
---|
120 | of the provider initialization function. See L<provider(7)/Provider>
|
---|
121 | for a description of the initialization function. They are known as "upcalls".
|
---|
122 |
|
---|
123 | All these "functions" have a corresponding function type definition
|
---|
124 | named B<OSSL_FUNC_{name}_fn>, and a helper function to retrieve the
|
---|
125 | function pointer from a B<OSSL_DISPATCH> element named
|
---|
126 | B<OSSL_FUNC_{name}>.
|
---|
127 | For example, the "function" core_gettable_params() has these:
|
---|
128 |
|
---|
129 | typedef OSSL_PARAM *
|
---|
130 | (OSSL_FUNC_core_gettable_params_fn)(const OSSL_CORE_HANDLE *handle);
|
---|
131 | static ossl_inline OSSL_NAME_core_gettable_params_fn
|
---|
132 | OSSL_FUNC_core_gettable_params(const OSSL_DISPATCH *opf);
|
---|
133 |
|
---|
134 | B<OSSL_DISPATCH> arrays are indexed by numbers that are provided as
|
---|
135 | macros in L<openssl-core_dispatch.h(7)>, as follows:
|
---|
136 |
|
---|
137 | For I<in> (the B<OSSL_DISPATCH> array passed from F<libcrypto> to the
|
---|
138 | provider):
|
---|
139 |
|
---|
140 | core_gettable_params OSSL_FUNC_CORE_GETTABLE_PARAMS
|
---|
141 | core_get_params OSSL_FUNC_CORE_GET_PARAMS
|
---|
142 | core_thread_start OSSL_FUNC_CORE_THREAD_START
|
---|
143 | core_get_libctx OSSL_FUNC_CORE_GET_LIBCTX
|
---|
144 | core_new_error OSSL_FUNC_CORE_NEW_ERROR
|
---|
145 | core_set_error_debug OSSL_FUNC_CORE_SET_ERROR_DEBUG
|
---|
146 | core_vset_error OSSL_FUNC_CORE_VSET_ERROR
|
---|
147 | core_obj_add_sigid OSSL_FUNC_CORE_OBJ_ADD_SIGID
|
---|
148 | core_obj_create OSSL_FUNC_CORE_OBJ_CREATE
|
---|
149 | CRYPTO_malloc OSSL_FUNC_CRYPTO_MALLOC
|
---|
150 | CRYPTO_zalloc OSSL_FUNC_CRYPTO_ZALLOC
|
---|
151 | CRYPTO_free OSSL_FUNC_CRYPTO_FREE
|
---|
152 | CRYPTO_clear_free OSSL_FUNC_CRYPTO_CLEAR_FREE
|
---|
153 | CRYPTO_realloc OSSL_FUNC_CRYPTO_REALLOC
|
---|
154 | CRYPTO_clear_realloc OSSL_FUNC_CRYPTO_CLEAR_REALLOC
|
---|
155 | CRYPTO_secure_malloc OSSL_FUNC_CRYPTO_SECURE_MALLOC
|
---|
156 | CRYPTO_secure_zalloc OSSL_FUNC_CRYPTO_SECURE_ZALLOC
|
---|
157 | CRYPTO_secure_free OSSL_FUNC_CRYPTO_SECURE_FREE
|
---|
158 | CRYPTO_secure_clear_free OSSL_FUNC_CRYPTO_SECURE_CLEAR_FREE
|
---|
159 | CRYPTO_secure_allocated OSSL_FUNC_CRYPTO_SECURE_ALLOCATED
|
---|
160 | BIO_new_file OSSL_FUNC_BIO_NEW_FILE
|
---|
161 | BIO_new_mem_buf OSSL_FUNC_BIO_NEW_MEMBUF
|
---|
162 | BIO_read_ex OSSL_FUNC_BIO_READ_EX
|
---|
163 | BIO_write_ex OSSL_FUNC_BIO_WRITE_EX
|
---|
164 | BIO_up_ref OSSL_FUNC_BIO_UP_REF
|
---|
165 | BIO_free OSSL_FUNC_BIO_FREE
|
---|
166 | BIO_vprintf OSSL_FUNC_BIO_VPRINTF
|
---|
167 | BIO_vsnprintf OSSL_FUNC_BIO_VSNPRINTF
|
---|
168 | BIO_puts OSSL_FUNC_BIO_PUTS
|
---|
169 | BIO_gets OSSL_FUNC_BIO_GETS
|
---|
170 | BIO_ctrl OSSL_FUNC_BIO_CTRL
|
---|
171 | OPENSSL_cleanse OSSL_FUNC_OPENSSL_CLEANSE
|
---|
172 | OSSL_SELF_TEST_set_callback OSSL_FUNC_SELF_TEST_CB
|
---|
173 | ossl_rand_get_entropy OSSL_FUNC_GET_ENTROPY
|
---|
174 | ossl_rand_cleanup_entropy OSSL_FUNC_CLEANUP_ENTROPY
|
---|
175 | ossl_rand_get_nonce OSSL_FUNC_GET_NONCE
|
---|
176 | ossl_rand_cleanup_nonce OSSL_FUNC_CLEANUP_NONCE
|
---|
177 | provider_register_child_cb OSSL_FUNC_PROVIDER_REGISTER_CHILD_CB
|
---|
178 | provider_deregister_child_cb OSSL_FUNC_PROVIDER_DEREGISTER_CHILD_CB
|
---|
179 | provider_name OSSL_FUNC_PROVIDER_NAME
|
---|
180 | provider_get0_provider_ctx OSSL_FUNC_PROVIDER_GET0_PROVIDER_CTX
|
---|
181 | provider_get0_dispatch OSSL_FUNC_PROVIDER_GET0_DISPATCH
|
---|
182 | provider_up_ref OSSL_FUNC_PROVIDER_UP_REF
|
---|
183 | provider_free OSSL_FUNC_PROVIDER_FREE
|
---|
184 |
|
---|
185 | For I<*out> (the B<OSSL_DISPATCH> array passed from the provider to
|
---|
186 | F<libcrypto>):
|
---|
187 |
|
---|
188 | provider_teardown OSSL_FUNC_PROVIDER_TEARDOWN
|
---|
189 | provider_gettable_params OSSL_FUNC_PROVIDER_GETTABLE_PARAMS
|
---|
190 | provider_get_params OSSL_FUNC_PROVIDER_GET_PARAMS
|
---|
191 | provider_query_operation OSSL_FUNC_PROVIDER_QUERY_OPERATION
|
---|
192 | provider_unquery_operation OSSL_FUNC_PROVIDER_UNQUERY_OPERATION
|
---|
193 | provider_get_reason_strings OSSL_FUNC_PROVIDER_GET_REASON_STRINGS
|
---|
194 | provider_get_capabilities OSSL_FUNC_PROVIDER_GET_CAPABILITIES
|
---|
195 | provider_self_test OSSL_FUNC_PROVIDER_SELF_TEST
|
---|
196 |
|
---|
197 | =head2 Core functions
|
---|
198 |
|
---|
199 | core_gettable_params() returns a constant array of descriptor
|
---|
200 | B<OSSL_PARAM>, for parameters that core_get_params() can handle.
|
---|
201 |
|
---|
202 | core_get_params() retrieves parameters from the core for the given I<handle>.
|
---|
203 | See L</Core parameters> below for a description of currently known
|
---|
204 | parameters.
|
---|
205 |
|
---|
206 | The core_thread_start() function informs the core that the provider has stated
|
---|
207 | an interest in the current thread. The core will inform the provider when the
|
---|
208 | thread eventually stops. It must be passed the I<handle> for this provider, as
|
---|
209 | well as a callback I<handfn> which will be called when the thread stops. The
|
---|
210 | callback will subsequently be called, with the supplied argument I<arg>, from
|
---|
211 | the thread that is stopping and gets passed the provider context as an
|
---|
212 | argument. This may be useful to perform thread specific clean up such as
|
---|
213 | freeing thread local variables.
|
---|
214 |
|
---|
215 | core_get_libctx() retrieves the core context in which the library
|
---|
216 | object for the current provider is stored, accessible through the I<handle>.
|
---|
217 | This function is useful only for built-in providers such as the default
|
---|
218 | provider. Never cast this to OSSL_LIB_CTX in a provider that is not
|
---|
219 | built-in as the OSSL_LIB_CTX of the library loading the provider might be
|
---|
220 | a completely different structure than the OSSL_LIB_CTX of the library the
|
---|
221 | provider is linked to. Use L<OSSL_LIB_CTX_new_child(3)> instead to obtain
|
---|
222 | a proper library context that is linked to the application library context.
|
---|
223 |
|
---|
224 | core_new_error(), core_set_error_debug() and core_vset_error() are
|
---|
225 | building blocks for reporting an error back to the core, with
|
---|
226 | reference to the I<handle>.
|
---|
227 |
|
---|
228 | =over 4
|
---|
229 |
|
---|
230 | =item core_new_error()
|
---|
231 |
|
---|
232 | allocates a new thread specific error record.
|
---|
233 |
|
---|
234 | This corresponds to the OpenSSL function L<ERR_new(3)>.
|
---|
235 |
|
---|
236 | =item core_set_error_debug()
|
---|
237 |
|
---|
238 | sets debugging information in the current thread specific error
|
---|
239 | record.
|
---|
240 | The debugging information includes the name of the file I<file>, the
|
---|
241 | line I<line> and the function name I<func> where the error occurred.
|
---|
242 |
|
---|
243 | This corresponds to the OpenSSL function L<ERR_set_debug(3)>.
|
---|
244 |
|
---|
245 | =item core_vset_error()
|
---|
246 |
|
---|
247 | sets the I<reason> for the error, along with any addition data.
|
---|
248 | The I<reason> is a number defined by the provider and used to index
|
---|
249 | the reason strings table that's returned by
|
---|
250 | provider_get_reason_strings().
|
---|
251 | The additional data is given as a format string I<fmt> and a set of
|
---|
252 | arguments I<args>, which are treated in the same manner as with
|
---|
253 | BIO_vsnprintf().
|
---|
254 | I<file> and I<line> may also be passed to indicate exactly where the
|
---|
255 | error occurred or was reported.
|
---|
256 |
|
---|
257 | This corresponds to the OpenSSL function L<ERR_vset_error(3)>.
|
---|
258 |
|
---|
259 | =back
|
---|
260 |
|
---|
261 | The core_obj_create() function registers a new OID and associated short name
|
---|
262 | I<sn> and long name I<ln> for the given I<handle>. It is similar to the OpenSSL
|
---|
263 | function L<OBJ_create(3)> except that it returns 1 on success or 0 on failure.
|
---|
264 | It will treat as success the case where the OID already exists (even if the
|
---|
265 | short name I<sn> or long name I<ln> provided as arguments differ from those
|
---|
266 | associated with the existing OID, in which case the new names are not
|
---|
267 | associated).
|
---|
268 | This function is not thread safe.
|
---|
269 |
|
---|
270 | The core_obj_add_sigid() function registers a new composite signature algorithm
|
---|
271 | (I<sign_name>) consisting of an underlying signature algorithm (I<pkey_name>)
|
---|
272 | and digest algorithm (I<digest_name>) for the given I<handle>. It assumes that
|
---|
273 | the OIDs for the composite signature algorithm as well as for the underlying
|
---|
274 | signature and digest algorithms are either already known to OpenSSL or have been
|
---|
275 | registered via a call to core_obj_create(). It corresponds to the OpenSSL
|
---|
276 | function L<OBJ_add_sigid(3)>, except that the objects are identified by name
|
---|
277 | rather than a numeric NID. Any name (OID, short name or long name) can be used
|
---|
278 | to identify the object. It will treat as success the case where the composite
|
---|
279 | signature algorithm already exists (even if registered against a different
|
---|
280 | underlying signature or digest algorithm). For I<digest_name>, NULL or an
|
---|
281 | empty string is permissible for signature algorithms that do not need a digest
|
---|
282 | to operate correctly. The function returns 1 on success or 0 on failure.
|
---|
283 | This function is not thread safe.
|
---|
284 |
|
---|
285 | CRYPTO_malloc(), CRYPTO_zalloc(), CRYPTO_free(), CRYPTO_clear_free(),
|
---|
286 | CRYPTO_realloc(), CRYPTO_clear_realloc(), CRYPTO_secure_malloc(),
|
---|
287 | CRYPTO_secure_zalloc(), CRYPTO_secure_free(),
|
---|
288 | CRYPTO_secure_clear_free(), CRYPTO_secure_allocated(),
|
---|
289 | BIO_new_file(), BIO_new_mem_buf(), BIO_read_ex(), BIO_write_ex(), BIO_up_ref(),
|
---|
290 | BIO_free(), BIO_vprintf(), BIO_vsnprintf(), BIO_gets(), BIO_puts(),
|
---|
291 | BIO_ctrl(), OPENSSL_cleanse() and
|
---|
292 | OPENSSL_hexstr2buf() correspond exactly to the public functions with
|
---|
293 | the same name. As a matter of fact, the pointers in the B<OSSL_DISPATCH>
|
---|
294 | array are typically direct pointers to those public functions. Note that the BIO
|
---|
295 | functions take an B<OSSL_CORE_BIO> type rather than the standard B<BIO>
|
---|
296 | type. This is to ensure that a provider does not mix BIOs from the core
|
---|
297 | with BIOs used on the provider side (the two are not compatible).
|
---|
298 | OSSL_SELF_TEST_set_callback() is used to set an optional callback that can be
|
---|
299 | passed into a provider. This may be ignored by a provider.
|
---|
300 |
|
---|
301 | get_entropy() retrieves seeding material from the operating system.
|
---|
302 | The seeding material will have at least I<entropy> bytes of randomness and the
|
---|
303 | output will have at least I<min_len> and at most I<max_len> bytes.
|
---|
304 | The buffer address is stored in I<*pout> and the buffer length is
|
---|
305 | returned to the caller. On error, zero is returned.
|
---|
306 |
|
---|
307 | cleanup_entropy() is used to clean up and free the buffer returned by
|
---|
308 | get_entropy(). The entropy pointer returned by get_entropy() is passed in
|
---|
309 | B<buf> and its length in B<len>.
|
---|
310 |
|
---|
311 | get_nonce() retrieves a nonce using the passed I<salt> parameter
|
---|
312 | of length I<salt_len> and operating system specific information.
|
---|
313 | The I<salt> should contain uniquely identifying information and this is
|
---|
314 | included, in an unspecified manner, as part of the output.
|
---|
315 | The output is stored in a buffer which contrains at least I<min_len> and at
|
---|
316 | most I<max_len> bytes. The buffer address is stored in I<*pout> and the
|
---|
317 | buffer length returned to the caller. On error, zero is returned.
|
---|
318 |
|
---|
319 | cleanup_nonce() is used to clean up and free the buffer returned by
|
---|
320 | get_nonce(). The nonce pointer returned by get_nonce() is passed in
|
---|
321 | B<buf> and its length in B<len>.
|
---|
322 |
|
---|
323 | provider_register_child_cb() registers callbacks for being informed about the
|
---|
324 | loading and unloading of providers in the application's library context.
|
---|
325 | I<handle> is this provider's handle and I<cbdata> is this provider's data
|
---|
326 | that will be passed back to the callbacks. It returns 1 on success or 0
|
---|
327 | otherwise. These callbacks may be called while holding locks in libcrypto. In
|
---|
328 | order to avoid deadlocks the callback implementation must not be long running
|
---|
329 | and must not call other OpenSSL API functions or upcalls.
|
---|
330 |
|
---|
331 | I<create_cb> is a callback that will be called when a new provider is loaded
|
---|
332 | into the application's library context. It is also called for any providers that
|
---|
333 | are already loaded at the point that this callback is registered. The callback
|
---|
334 | is passed the handle being used for the new provider being loadded and this
|
---|
335 | provider's data in I<cbdata>. It should return 1 on success or 0 on failure.
|
---|
336 |
|
---|
337 | I<remove_cb> is a callback that will be called when a new provider is unloaded
|
---|
338 | from the application's library context. It is passed the handle being used for
|
---|
339 | the provider being unloaded and this provider's data in I<cbdata>. It should
|
---|
340 | return 1 on success or 0 on failure.
|
---|
341 |
|
---|
342 | I<global_props_cb> is a callback that will be called when the global properties
|
---|
343 | from the parent library context are changed. It should return 1 on success
|
---|
344 | or 0 on failure.
|
---|
345 |
|
---|
346 | provider_deregister_child_cb() unregisters callbacks previously registered via
|
---|
347 | provider_register_child_cb(). If provider_register_child_cb() has been called
|
---|
348 | then provider_deregister_child_cb() should be called at or before the point that
|
---|
349 | this provider's teardown function is called.
|
---|
350 |
|
---|
351 | provider_name() returns a string giving the name of the provider identified by
|
---|
352 | I<handle>.
|
---|
353 |
|
---|
354 | provider_get0_provider_ctx() returns the provider context that is associated
|
---|
355 | with the provider identified by I<prov>.
|
---|
356 |
|
---|
357 | provider_get0_dispatch() gets the dispatch table registered by the provider
|
---|
358 | identified by I<prov> when it initialised.
|
---|
359 |
|
---|
360 | provider_up_ref() increments the reference count on the provider I<prov>. If
|
---|
361 | I<activate> is nonzero then the provider is also loaded if it is not already
|
---|
362 | loaded. It returns 1 on success or 0 on failure.
|
---|
363 |
|
---|
364 | provider_free() decrements the reference count on the provider I<prov>. If
|
---|
365 | I<deactivate> is nonzero then the provider is also unloaded if it is not
|
---|
366 | already loaded. It returns 1 on success or 0 on failure.
|
---|
367 |
|
---|
368 | =head2 Provider functions
|
---|
369 |
|
---|
370 | provider_teardown() is called when a provider is shut down and removed
|
---|
371 | from the core's provider store.
|
---|
372 | It must free the passed I<provctx>.
|
---|
373 |
|
---|
374 | provider_gettable_params() should return a constant array of
|
---|
375 | descriptor B<OSSL_PARAM>, for parameters that provider_get_params()
|
---|
376 | can handle.
|
---|
377 |
|
---|
378 | provider_get_params() should process the B<OSSL_PARAM> array
|
---|
379 | I<params>, setting the values of the parameters it understands.
|
---|
380 |
|
---|
381 | provider_query_operation() should return a constant B<OSSL_ALGORITHM>
|
---|
382 | that corresponds to the given I<operation_id>.
|
---|
383 | It should indicate if the core may store a reference to this array by
|
---|
384 | setting I<*no_store> to 0 (core may store a reference) or 1 (core may
|
---|
385 | not store a reference).
|
---|
386 |
|
---|
387 | provider_unquery_operation() informs the provider that the result of a
|
---|
388 | provider_query_operation() is no longer directly required and that the function
|
---|
389 | pointers have been copied. The I<operation_id> should match that passed to
|
---|
390 | provider_query_operation() and I<algs> should be its return value.
|
---|
391 |
|
---|
392 | provider_get_reason_strings() should return a constant B<OSSL_ITEM>
|
---|
393 | array that provides reason strings for reason codes the provider may
|
---|
394 | use when reporting errors using core_put_error().
|
---|
395 |
|
---|
396 | The provider_get_capabilities() function should call the callback I<cb> passing
|
---|
397 | it a set of B<OSSL_PARAM>s and the caller supplied argument I<arg>. The
|
---|
398 | B<OSSL_PARAM>s should provide details about the capability with the name given
|
---|
399 | in the I<capability> argument relevant for the provider context I<provctx>. If a
|
---|
400 | provider supports multiple capabilities with the given name then it may call the
|
---|
401 | callback multiple times (one for each capability). Capabilities can be useful for
|
---|
402 | describing the services that a provider can offer. For further details see the
|
---|
403 | L</CAPABILITIES> section below. It should return 1 on success or 0 on error.
|
---|
404 |
|
---|
405 | The provider_self_test() function should perform known answer tests on a subset
|
---|
406 | of the algorithms that it uses, and may also verify the integrity of the
|
---|
407 | provider module. It should return 1 on success or 0 on error. It will return 1
|
---|
408 | if this function is not used.
|
---|
409 |
|
---|
410 | None of these functions are mandatory, but a provider is fairly
|
---|
411 | useless without at least provider_query_operation(), and
|
---|
412 | provider_gettable_params() is fairly useless if not accompanied by
|
---|
413 | provider_get_params().
|
---|
414 |
|
---|
415 | =head2 Provider parameters
|
---|
416 |
|
---|
417 | provider_get_params() can return the following provider parameters to the core:
|
---|
418 |
|
---|
419 | =over 4
|
---|
420 |
|
---|
421 | =item "name" (B<OSSL_PROV_PARAM_NAME>) <UTF8 string ptr>
|
---|
422 |
|
---|
423 | This points to a string that should give a unique name for the provider.
|
---|
424 |
|
---|
425 | =item "version" (B<OSSL_PROV_PARAM_VERSION>) <UTF8 string ptr>
|
---|
426 |
|
---|
427 | This points to a string that is a version number associated with this provider.
|
---|
428 | OpenSSL in-built providers use OPENSSL_VERSION_STR, but this may be different
|
---|
429 | for any third party provider. This string is for informational purposes only.
|
---|
430 |
|
---|
431 | =item "buildinfo" (B<OSSL_PROV_PARAM_BUILDINFO>) <UTF8 string ptr>
|
---|
432 |
|
---|
433 | This points to a string that is a build information associated with this provider.
|
---|
434 | OpenSSL in-built providers use OPENSSL_FULL_VERSION_STR, but this may be
|
---|
435 | different for any third party provider.
|
---|
436 |
|
---|
437 | =item "status" (B<OSSL_PROV_PARAM_STATUS>) <unsigned integer>
|
---|
438 |
|
---|
439 | This returns 0 if the provider has entered an error state, otherwise it returns
|
---|
440 | 1.
|
---|
441 |
|
---|
442 | =back
|
---|
443 |
|
---|
444 | provider_gettable_params() should return the above parameters.
|
---|
445 |
|
---|
446 |
|
---|
447 | =head2 Core parameters
|
---|
448 |
|
---|
449 | core_get_params() can retrieve the following core parameters for each provider:
|
---|
450 |
|
---|
451 | =over 4
|
---|
452 |
|
---|
453 | =item "openssl-version" (B<OSSL_PROV_PARAM_CORE_VERSION>) <UTF8 string ptr>
|
---|
454 |
|
---|
455 | This points to the OpenSSL libraries' full version string, i.e. the string
|
---|
456 | expanded from the macro B<OPENSSL_VERSION_STR>.
|
---|
457 |
|
---|
458 | =item "provider-name" (B<OSSL_PROV_PARAM_CORE_PROV_NAME>) <UTF8 string ptr>
|
---|
459 |
|
---|
460 | This points to the OpenSSL libraries' idea of what the calling provider is named.
|
---|
461 |
|
---|
462 | =item "module-filename" (B<OSSL_PROV_PARAM_CORE_MODULE_FILENAME>) <UTF8 string ptr>
|
---|
463 |
|
---|
464 | This points to a string containing the full filename of the providers
|
---|
465 | module file.
|
---|
466 |
|
---|
467 | =back
|
---|
468 |
|
---|
469 | Additionally, provider specific configuration parameters from the
|
---|
470 | config file are available, in dotted name form.
|
---|
471 | The dotted name form is a concatenation of section names and final
|
---|
472 | config command name separated by periods.
|
---|
473 |
|
---|
474 | For example, let's say we have the following config example:
|
---|
475 |
|
---|
476 | config_diagnostics = 1
|
---|
477 | openssl_conf = openssl_init
|
---|
478 |
|
---|
479 | [openssl_init]
|
---|
480 | providers = providers_sect
|
---|
481 |
|
---|
482 | [providers_sect]
|
---|
483 | foo = foo_sect
|
---|
484 |
|
---|
485 | [foo_sect]
|
---|
486 | activate = 1
|
---|
487 | data1 = 2
|
---|
488 | data2 = str
|
---|
489 | more = foo_more
|
---|
490 |
|
---|
491 | [foo_more]
|
---|
492 | data3 = foo,bar
|
---|
493 |
|
---|
494 | The provider will have these additional parameters available:
|
---|
495 |
|
---|
496 | =over 4
|
---|
497 |
|
---|
498 | =item "activate"
|
---|
499 |
|
---|
500 | pointing at the string "1"
|
---|
501 |
|
---|
502 | =item "data1"
|
---|
503 |
|
---|
504 | pointing at the string "2"
|
---|
505 |
|
---|
506 | =item "data2"
|
---|
507 |
|
---|
508 | pointing at the string "str"
|
---|
509 |
|
---|
510 | =item "more.data3"
|
---|
511 |
|
---|
512 | pointing at the string "foo,bar"
|
---|
513 |
|
---|
514 | =back
|
---|
515 |
|
---|
516 | For more information on handling parameters, see L<OSSL_PARAM(3)> as
|
---|
517 | L<OSSL_PARAM_int(3)>.
|
---|
518 |
|
---|
519 | =head1 CAPABILITIES
|
---|
520 |
|
---|
521 | Capabilities describe some of the services that a provider can offer.
|
---|
522 | Applications can query the capabilities to discover those services.
|
---|
523 |
|
---|
524 | =head3 "TLS-GROUP" Capability
|
---|
525 |
|
---|
526 | The "TLS-GROUP" capability can be queried by libssl to discover the list of
|
---|
527 | TLS groups that a provider can support. Each group supported can be used for
|
---|
528 | I<key exchange> (KEX) or I<key encapsulation method> (KEM) during a TLS
|
---|
529 | handshake.
|
---|
530 | TLS clients can advertise the list of TLS groups they support in the
|
---|
531 | supported_groups extension, and TLS servers can select a group from the offered
|
---|
532 | list that they also support. In this way a provider can add to the list of
|
---|
533 | groups that libssl already supports with additional ones.
|
---|
534 |
|
---|
535 | Each TLS group that a provider supports should be described via the callback
|
---|
536 | passed in through the provider_get_capabilities function. Each group should have
|
---|
537 | the following details supplied (all are mandatory, except
|
---|
538 | B<OSSL_CAPABILITY_TLS_GROUP_IS_KEM>):
|
---|
539 |
|
---|
540 | =over 4
|
---|
541 |
|
---|
542 | =item "tls-group-name" (B<OSSL_CAPABILITY_TLS_GROUP_NAME>) <UTF8 string>
|
---|
543 |
|
---|
544 | The name of the group as given in the IANA TLS Supported Groups registry
|
---|
545 | L<https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8>.
|
---|
546 |
|
---|
547 | =item "tls-group-name-internal" (B<OSSL_CAPABILITY_TLS_GROUP_NAME_INTERNAL>) <UTF8 string>
|
---|
548 |
|
---|
549 | The name of the group as known by the provider. This could be the same as the
|
---|
550 | "tls-group-name", but does not have to be.
|
---|
551 |
|
---|
552 | =item "tls-group-id" (B<OSSL_CAPABILITY_TLS_GROUP_ID>) <unsigned integer>
|
---|
553 |
|
---|
554 | The TLS group id value as given in the IANA TLS Supported Groups registry.
|
---|
555 |
|
---|
556 | =item "tls-group-alg" (B<OSSL_CAPABILITY_TLS_GROUP_ALG>) <UTF8 string>
|
---|
557 |
|
---|
558 | The name of a Key Management algorithm that the provider offers and that should
|
---|
559 | be used with this group. Keys created should be able to support I<key exchange>
|
---|
560 | or I<key encapsulation method> (KEM), as implied by the optional
|
---|
561 | B<OSSL_CAPABILITY_TLS_GROUP_IS_KEM> flag.
|
---|
562 | The algorithm must support key and parameter generation as well as the
|
---|
563 | key/parameter generation parameter, B<OSSL_PKEY_PARAM_GROUP_NAME>. The group
|
---|
564 | name given via "tls-group-name-internal" above will be passed via
|
---|
565 | B<OSSL_PKEY_PARAM_GROUP_NAME> when libssl wishes to generate keys/parameters.
|
---|
566 |
|
---|
567 | =item "tls-group-sec-bits" (B<OSSL_CAPABILITY_TLS_GROUP_SECURITY_BITS>) <unsigned integer>
|
---|
568 |
|
---|
569 | The number of bits of security offered by keys in this group. The number of bits
|
---|
570 | should be comparable with the ones given in table 2 and 3 of the NIST SP800-57
|
---|
571 | document.
|
---|
572 |
|
---|
573 | =item "tls-group-is-kem" (B<OSSL_CAPABILITY_TLS_GROUP_IS_KEM>) <unsigned integer>
|
---|
574 |
|
---|
575 | Boolean flag to describe if the group should be used in I<key exchange> (KEX)
|
---|
576 | mode (0, default) or in I<key encapsulation method> (KEM) mode (1).
|
---|
577 |
|
---|
578 | This parameter is optional: if not specified, KEX mode is assumed as the default
|
---|
579 | mode for the group.
|
---|
580 |
|
---|
581 | In KEX mode, in a typical Diffie-Hellman fashion, both sides execute I<keygen>
|
---|
582 | then I<derive> against the peer public key. To operate in KEX mode, the group
|
---|
583 | implementation must support the provider functions as described in
|
---|
584 | L<provider-keyexch(7)>.
|
---|
585 |
|
---|
586 | In KEM mode, the client executes I<keygen> and sends its public key, the server
|
---|
587 | executes I<encapsulate> using the client's public key and sends back the
|
---|
588 | resulting I<ciphertext>, finally the client executes I<decapsulate> to retrieve
|
---|
589 | the same I<shared secret> generated by the server's I<encapsulate>. To operate
|
---|
590 | in KEM mode, the group implementation must support the provider functions as
|
---|
591 | described in L<provider-kem(7)>.
|
---|
592 |
|
---|
593 | Both in KEX and KEM mode, the resulting I<shared secret> is then used according
|
---|
594 | to the protocol specification.
|
---|
595 |
|
---|
596 | =item "tls-min-tls" (B<OSSL_CAPABILITY_TLS_GROUP_MIN_TLS>) <integer>
|
---|
597 |
|
---|
598 | =item "tls-max-tls" (B<OSSL_CAPABILITY_TLS_GROUP_MAX_TLS>) <integer>
|
---|
599 |
|
---|
600 | =item "tls-min-dtls" (B<OSSL_CAPABILITY_TLS_GROUP_MIN_DTLS>) <integer>
|
---|
601 |
|
---|
602 | =item "tls-max-dtls" (B<OSSL_CAPABILITY_TLS_GROUP_MAX_DTLS>) <integer>
|
---|
603 |
|
---|
604 | These parameters can be used to describe the minimum and maximum TLS and DTLS
|
---|
605 | versions supported by the group. The values equate to the on-the-wire encoding
|
---|
606 | of the various TLS versions. For example TLSv1.3 is 0x0304 (772 decimal), and
|
---|
607 | TLSv1.2 is 0x0303 (771 decimal). A 0 indicates that there is no defined minimum
|
---|
608 | or maximum. A -1 indicates that the group should not be used in that protocol.
|
---|
609 |
|
---|
610 | =back
|
---|
611 |
|
---|
612 | =head1 EXAMPLES
|
---|
613 |
|
---|
614 | This is an example of a simple provider made available as a
|
---|
615 | dynamically loadable module.
|
---|
616 | It implements the fictitious algorithm C<FOO> for the fictitious
|
---|
617 | operation C<BAR>.
|
---|
618 |
|
---|
619 | #include <malloc.h>
|
---|
620 | #include <openssl/core.h>
|
---|
621 | #include <openssl/core_dispatch.h>
|
---|
622 |
|
---|
623 | /* Errors used in this provider */
|
---|
624 | #define E_MALLOC 1
|
---|
625 |
|
---|
626 | static const OSSL_ITEM reasons[] = {
|
---|
627 | { E_MALLOC, "memory allocation failure" }.
|
---|
628 | { 0, NULL } /* Termination */
|
---|
629 | };
|
---|
630 |
|
---|
631 | /*
|
---|
632 | * To ensure we get the function signature right, forward declare
|
---|
633 | * them using function types provided by openssl/core_dispatch.h
|
---|
634 | */
|
---|
635 | OSSL_FUNC_bar_newctx_fn foo_newctx;
|
---|
636 | OSSL_FUNC_bar_freectx_fn foo_freectx;
|
---|
637 | OSSL_FUNC_bar_init_fn foo_init;
|
---|
638 | OSSL_FUNC_bar_update_fn foo_update;
|
---|
639 | OSSL_FUNC_bar_final_fn foo_final;
|
---|
640 |
|
---|
641 | OSSL_FUNC_provider_query_operation_fn p_query;
|
---|
642 | OSSL_FUNC_provider_get_reason_strings_fn p_reasons;
|
---|
643 | OSSL_FUNC_provider_teardown_fn p_teardown;
|
---|
644 |
|
---|
645 | OSSL_provider_init_fn OSSL_provider_init;
|
---|
646 |
|
---|
647 | OSSL_FUNC_core_put_error *c_put_error = NULL;
|
---|
648 |
|
---|
649 | /* Provider context */
|
---|
650 | struct prov_ctx_st {
|
---|
651 | OSSL_CORE_HANDLE *handle;
|
---|
652 | }
|
---|
653 |
|
---|
654 | /* operation context for the algorithm FOO */
|
---|
655 | struct foo_ctx_st {
|
---|
656 | struct prov_ctx_st *provctx;
|
---|
657 | int b;
|
---|
658 | };
|
---|
659 |
|
---|
660 | static void *foo_newctx(void *provctx)
|
---|
661 | {
|
---|
662 | struct foo_ctx_st *fooctx = malloc(sizeof(*fooctx));
|
---|
663 |
|
---|
664 | if (fooctx != NULL)
|
---|
665 | fooctx->provctx = provctx;
|
---|
666 | else
|
---|
667 | c_put_error(provctx->handle, E_MALLOC, __FILE__, __LINE__);
|
---|
668 | return fooctx;
|
---|
669 | }
|
---|
670 |
|
---|
671 | static void foo_freectx(void *fooctx)
|
---|
672 | {
|
---|
673 | free(fooctx);
|
---|
674 | }
|
---|
675 |
|
---|
676 | static int foo_init(void *vfooctx)
|
---|
677 | {
|
---|
678 | struct foo_ctx_st *fooctx = vfooctx;
|
---|
679 |
|
---|
680 | fooctx->b = 0x33;
|
---|
681 | }
|
---|
682 |
|
---|
683 | static int foo_update(void *vfooctx, unsigned char *in, size_t inl)
|
---|
684 | {
|
---|
685 | struct foo_ctx_st *fooctx = vfooctx;
|
---|
686 |
|
---|
687 | /* did you expect something serious? */
|
---|
688 | if (inl == 0)
|
---|
689 | return 1;
|
---|
690 | for (; inl-- > 0; in++)
|
---|
691 | *in ^= fooctx->b;
|
---|
692 | return 1;
|
---|
693 | }
|
---|
694 |
|
---|
695 | static int foo_final(void *vfooctx)
|
---|
696 | {
|
---|
697 | struct foo_ctx_st *fooctx = vfooctx;
|
---|
698 |
|
---|
699 | fooctx->b = 0x66;
|
---|
700 | }
|
---|
701 |
|
---|
702 | static const OSSL_DISPATCH foo_fns[] = {
|
---|
703 | { OSSL_FUNC_BAR_NEWCTX, (void (*)(void))foo_newctx },
|
---|
704 | { OSSL_FUNC_BAR_FREECTX, (void (*)(void))foo_freectx },
|
---|
705 | { OSSL_FUNC_BAR_INIT, (void (*)(void))foo_init },
|
---|
706 | { OSSL_FUNC_BAR_UPDATE, (void (*)(void))foo_update },
|
---|
707 | { OSSL_FUNC_BAR_FINAL, (void (*)(void))foo_final },
|
---|
708 | { 0, NULL }
|
---|
709 | };
|
---|
710 |
|
---|
711 | static const OSSL_ALGORITHM bars[] = {
|
---|
712 | { "FOO", "provider=chumbawamba", foo_fns },
|
---|
713 | { NULL, NULL, NULL }
|
---|
714 | };
|
---|
715 |
|
---|
716 | static const OSSL_ALGORITHM *p_query(void *provctx, int operation_id,
|
---|
717 | int *no_store)
|
---|
718 | {
|
---|
719 | switch (operation_id) {
|
---|
720 | case OSSL_OP_BAR:
|
---|
721 | return bars;
|
---|
722 | }
|
---|
723 | return NULL;
|
---|
724 | }
|
---|
725 |
|
---|
726 | static const OSSL_ITEM *p_reasons(void *provctx)
|
---|
727 | {
|
---|
728 | return reasons;
|
---|
729 | }
|
---|
730 |
|
---|
731 | static void p_teardown(void *provctx)
|
---|
732 | {
|
---|
733 | free(provctx);
|
---|
734 | }
|
---|
735 |
|
---|
736 | static const OSSL_DISPATCH prov_fns[] = {
|
---|
737 | { OSSL_FUNC_PROVIDER_TEARDOWN, (void (*)(void))p_teardown },
|
---|
738 | { OSSL_FUNC_PROVIDER_QUERY_OPERATION, (void (*)(void))p_query },
|
---|
739 | { OSSL_FUNC_PROVIDER_GET_REASON_STRINGS, (void (*)(void))p_reasons },
|
---|
740 | { 0, NULL }
|
---|
741 | };
|
---|
742 |
|
---|
743 | int OSSL_provider_init(const OSSL_CORE_HANDLE *handle,
|
---|
744 | const OSSL_DISPATCH *in,
|
---|
745 | const OSSL_DISPATCH **out,
|
---|
746 | void **provctx)
|
---|
747 | {
|
---|
748 | struct prov_ctx_st *pctx = NULL;
|
---|
749 |
|
---|
750 | for (; in->function_id != 0; in++)
|
---|
751 | switch (in->function_id) {
|
---|
752 | case OSSL_FUNC_CORE_PUT_ERROR:
|
---|
753 | c_put_error = OSSL_FUNC_core_put_error(in);
|
---|
754 | break;
|
---|
755 | }
|
---|
756 |
|
---|
757 | *out = prov_fns;
|
---|
758 |
|
---|
759 | if ((pctx = malloc(sizeof(*pctx))) == NULL) {
|
---|
760 | /*
|
---|
761 | * ALEA IACTA EST, if the core retrieves the reason table
|
---|
762 | * regardless, that string will be displayed, otherwise not.
|
---|
763 | */
|
---|
764 | c_put_error(handle, E_MALLOC, __FILE__, __LINE__);
|
---|
765 | return 0;
|
---|
766 | }
|
---|
767 | pctx->handle = handle;
|
---|
768 | return 1;
|
---|
769 | }
|
---|
770 |
|
---|
771 | This relies on a few things existing in F<openssl/core_dispatch.h>:
|
---|
772 |
|
---|
773 | #define OSSL_OP_BAR 4711
|
---|
774 |
|
---|
775 | #define OSSL_FUNC_BAR_NEWCTX 1
|
---|
776 | typedef void *(OSSL_FUNC_bar_newctx_fn)(void *provctx);
|
---|
777 | static ossl_inline OSSL_FUNC_bar_newctx(const OSSL_DISPATCH *opf)
|
---|
778 | { return (OSSL_FUNC_bar_newctx_fn *)opf->function; }
|
---|
779 |
|
---|
780 | #define OSSL_FUNC_BAR_FREECTX 2
|
---|
781 | typedef void (OSSL_FUNC_bar_freectx_fn)(void *ctx);
|
---|
782 | static ossl_inline OSSL_FUNC_bar_newctx(const OSSL_DISPATCH *opf)
|
---|
783 | { return (OSSL_FUNC_bar_freectx_fn *)opf->function; }
|
---|
784 |
|
---|
785 | #define OSSL_FUNC_BAR_INIT 3
|
---|
786 | typedef void *(OSSL_FUNC_bar_init_fn)(void *ctx);
|
---|
787 | static ossl_inline OSSL_FUNC_bar_init(const OSSL_DISPATCH *opf)
|
---|
788 | { return (OSSL_FUNC_bar_init_fn *)opf->function; }
|
---|
789 |
|
---|
790 | #define OSSL_FUNC_BAR_UPDATE 4
|
---|
791 | typedef void *(OSSL_FUNC_bar_update_fn)(void *ctx,
|
---|
792 | unsigned char *in, size_t inl);
|
---|
793 | static ossl_inline OSSL_FUNC_bar_update(const OSSL_DISPATCH *opf)
|
---|
794 | { return (OSSL_FUNC_bar_update_fn *)opf->function; }
|
---|
795 |
|
---|
796 | #define OSSL_FUNC_BAR_FINAL 5
|
---|
797 | typedef void *(OSSL_FUNC_bar_final_fn)(void *ctx);
|
---|
798 | static ossl_inline OSSL_FUNC_bar_final(const OSSL_DISPATCH *opf)
|
---|
799 | { return (OSSL_FUNC_bar_final_fn *)opf->function; }
|
---|
800 |
|
---|
801 | =head1 SEE ALSO
|
---|
802 |
|
---|
803 | L<provider(7)>
|
---|
804 |
|
---|
805 | =head1 HISTORY
|
---|
806 |
|
---|
807 | The concept of providers and everything surrounding them was
|
---|
808 | introduced in OpenSSL 3.0.
|
---|
809 |
|
---|
810 | =head1 COPYRIGHT
|
---|
811 |
|
---|
812 | Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved.
|
---|
813 |
|
---|
814 | Licensed under the Apache License 2.0 (the "License"). You may not use
|
---|
815 | this file except in compliance with the License. You can obtain a copy
|
---|
816 | in the file LICENSE in the source distribution or at
|
---|
817 | L<https://www.openssl.org/source/license.html>.
|
---|
818 |
|
---|
819 | =cut
|
---|