1*b077aed3SPierre Pronchery=pod 2*b077aed3SPierre Pronchery 3*b077aed3SPierre Pronchery=head1 NAME 4*b077aed3SPierre Pronchery 5*b077aed3SPierre Proncheryprovider-encoder - The OSSL_ENCODER library E<lt>-E<gt> provider functions 6*b077aed3SPierre Pronchery 7*b077aed3SPierre Pronchery=head1 SYNOPSIS 8*b077aed3SPierre Pronchery 9*b077aed3SPierre Pronchery #include <openssl/core_dispatch.h> 10*b077aed3SPierre Pronchery 11*b077aed3SPierre Pronchery /* 12*b077aed3SPierre Pronchery * None of these are actual functions, but are displayed like this for 13*b077aed3SPierre Pronchery * the function signatures for functions that are offered as function 14*b077aed3SPierre Pronchery * pointers in OSSL_DISPATCH arrays. 15*b077aed3SPierre Pronchery */ 16*b077aed3SPierre Pronchery 17*b077aed3SPierre Pronchery /* Encoder parameter accessor and descriptor */ 18*b077aed3SPierre Pronchery const OSSL_PARAM *OSSL_FUNC_encoder_gettable_params(void *provctx); 19*b077aed3SPierre Pronchery int OSSL_FUNC_encoder_get_params(OSSL_PARAM params[]); 20*b077aed3SPierre Pronchery 21*b077aed3SPierre Pronchery /* Functions to construct / destruct / manipulate the encoder context */ 22*b077aed3SPierre Pronchery void *OSSL_FUNC_encoder_newctx(void *provctx); 23*b077aed3SPierre Pronchery void OSSL_FUNC_encoder_freectx(void *ctx); 24*b077aed3SPierre Pronchery int OSSL_FUNC_encoder_set_ctx_params(void *ctx, const OSSL_PARAM params[]); 25*b077aed3SPierre Pronchery const OSSL_PARAM *OSSL_FUNC_encoder_settable_ctx_params(void *provctx); 26*b077aed3SPierre Pronchery 27*b077aed3SPierre Pronchery /* Functions to check selection support */ 28*b077aed3SPierre Pronchery int OSSL_FUNC_encoder_does_selection(void *provctx, int selection); 29*b077aed3SPierre Pronchery 30*b077aed3SPierre Pronchery /* Functions to encode object data */ 31*b077aed3SPierre Pronchery int OSSL_FUNC_encoder_encode(void *ctx, OSSL_CORE_BIO *out, 32*b077aed3SPierre Pronchery const void *obj_raw, 33*b077aed3SPierre Pronchery const OSSL_PARAM obj_abstract[], 34*b077aed3SPierre Pronchery int selection, 35*b077aed3SPierre Pronchery OSSL_PASSPHRASE_CALLBACK *cb, 36*b077aed3SPierre Pronchery void *cbarg); 37*b077aed3SPierre Pronchery 38*b077aed3SPierre Pronchery /* Functions to import and free a temporary object to be encoded */ 39*b077aed3SPierre Pronchery void *OSSL_FUNC_encoder_import_object(void *ctx, int selection, 40*b077aed3SPierre Pronchery const OSSL_PARAM params[]); 41*b077aed3SPierre Pronchery void OSSL_FUNC_encoder_free_object(void *obj); 42*b077aed3SPierre Pronchery 43*b077aed3SPierre Pronchery 44*b077aed3SPierre Pronchery=head1 DESCRIPTION 45*b077aed3SPierre Pronchery 46*b077aed3SPierre ProncheryI<We use the wide term "encode" in this manual. This includes but is 47*b077aed3SPierre Proncherynot limited to serialization.> 48*b077aed3SPierre Pronchery 49*b077aed3SPierre ProncheryThe ENCODER operation is a generic method to encode a provider-native 50*b077aed3SPierre Proncheryobject (I<obj_raw>) or an object abstraction (I<object_abstract>, see 51*b077aed3SPierre ProncheryL<provider-object(7)>) into an encoded form, and write the result to 52*b077aed3SPierre Proncherythe given OSSL_CORE_BIO. If the caller wants to get the encoded 53*b077aed3SPierre Proncherystream to memory, it should provide a L<BIO_s_mem(3)> B<BIO>. 54*b077aed3SPierre Pronchery 55*b077aed3SPierre ProncheryThe encoder doesn't need to know more about the B<OSSL_CORE_BIO> 56*b077aed3SPierre Proncherypointer than being able to pass it to the appropriate BIO upcalls (see 57*b077aed3SPierre ProncheryL<provider-base(7)/Core functions>). 58*b077aed3SPierre Pronchery 59*b077aed3SPierre ProncheryThe ENCODER implementation may be part of a chain, where data is 60*b077aed3SPierre Proncherypassed from one to the next. For example, there may be an 61*b077aed3SPierre Proncheryimplementation to encode an object to DER (that object is assumed to 62*b077aed3SPierre Proncherybe provider-native and thereby passed via I<obj_raw>), and another one 63*b077aed3SPierre Proncherythat encodes DER to PEM (that one would receive the DER encoding via 64*b077aed3SPierre ProncheryI<obj_abstract>). 65*b077aed3SPierre Pronchery 66*b077aed3SPierre Pronchery=begin comment 67*b077aed3SPierre Pronchery 68*b077aed3SPierre ProncheryHaving the DER encoding passed via I<obj_abstract> may seem 69*b077aed3SPierre Proncherycomplicated. However, there may be associated meta-data, such as the 70*b077aed3SPierre Proncheryoriginal data type, that need to be passed alongside it, and since 71*b077aed3SPierre ProncheryL<provider-object(7)> already defines a way to pass such data, 72*b077aed3SPierre Proncheryinventing another way to do it makes things even more complicated. 73*b077aed3SPierre Pronchery 74*b077aed3SPierre Pronchery=end comment 75*b077aed3SPierre Pronchery 76*b077aed3SPierre ProncheryThe encoding using the L<OSSL_PARAM(3)> array form allows a 77*b077aed3SPierre Proncheryencoder to be used for data that's been exported from another 78*b077aed3SPierre Proncheryprovider, and thereby allow them to exist independently of each 79*b077aed3SPierre Proncheryother. 80*b077aed3SPierre Pronchery 81*b077aed3SPierre ProncheryThe encoding using a provider side object can only be safely used 82*b077aed3SPierre Proncherywith provider data coming from the same provider, for example keys 83*b077aed3SPierre Proncherywith the L<KEYMGMT|provider-keymgmt(7)> provider. 84*b077aed3SPierre Pronchery 85*b077aed3SPierre ProncheryAll "functions" mentioned here are passed as function pointers between 86*b077aed3SPierre ProncheryF<libcrypto> and the provider in L<OSSL_DISPATCH(3)> arrays via 87*b077aed3SPierre ProncheryL<OSSL_ALGORITHM(3)> arrays that are returned by the provider's 88*b077aed3SPierre Proncheryprovider_query_operation() function 89*b077aed3SPierre Pronchery(see L<provider-base(7)/Provider Functions>). 90*b077aed3SPierre Pronchery 91*b077aed3SPierre ProncheryAll these "functions" have a corresponding function type definition 92*b077aed3SPierre Proncherynamed B<OSSL_FUNC_{name}_fn>, and a helper function to retrieve the 93*b077aed3SPierre Proncheryfunction pointer from an L<OSSL_DISPATCH(3)> element named 94*b077aed3SPierre ProncheryB<OSSL_FUNC_{name}>. 95*b077aed3SPierre ProncheryFor example, the "function" OSSL_FUNC_encoder_encode() has these: 96*b077aed3SPierre Pronchery 97*b077aed3SPierre Pronchery typedef int 98*b077aed3SPierre Pronchery (OSSL_FUNC_encoder_encode_fn)(void *ctx, OSSL_CORE_BIO *out, 99*b077aed3SPierre Pronchery const void *obj_raw, 100*b077aed3SPierre Pronchery const OSSL_PARAM obj_abstract[], 101*b077aed3SPierre Pronchery int selection, 102*b077aed3SPierre Pronchery OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg); 103*b077aed3SPierre Pronchery static ossl_inline OSSL_FUNC_encoder_encode_fn 104*b077aed3SPierre Pronchery OSSL_FUNC_encoder_encode(const OSSL_DISPATCH *opf); 105*b077aed3SPierre Pronchery 106*b077aed3SPierre ProncheryL<OSSL_DISPATCH(3)> arrays are indexed by numbers that are provided as 107*b077aed3SPierre Proncherymacros in L<openssl-core_dispatch.h(7)>, as follows: 108*b077aed3SPierre Pronchery 109*b077aed3SPierre Pronchery OSSL_FUNC_encoder_get_params OSSL_FUNC_ENCODER_GET_PARAMS 110*b077aed3SPierre Pronchery OSSL_FUNC_encoder_gettable_params OSSL_FUNC_ENCODER_GETTABLE_PARAMS 111*b077aed3SPierre Pronchery 112*b077aed3SPierre Pronchery OSSL_FUNC_encoder_newctx OSSL_FUNC_ENCODER_NEWCTX 113*b077aed3SPierre Pronchery OSSL_FUNC_encoder_freectx OSSL_FUNC_ENCODER_FREECTX 114*b077aed3SPierre Pronchery OSSL_FUNC_encoder_set_ctx_params OSSL_FUNC_ENCODER_SET_CTX_PARAMS 115*b077aed3SPierre Pronchery OSSL_FUNC_encoder_settable_ctx_params OSSL_FUNC_ENCODER_SETTABLE_CTX_PARAMS 116*b077aed3SPierre Pronchery 117*b077aed3SPierre Pronchery OSSL_FUNC_encoder_does_selection OSSL_FUNC_ENCODER_DOES_SELECTION 118*b077aed3SPierre Pronchery 119*b077aed3SPierre Pronchery OSSL_FUNC_encoder_encode OSSL_FUNC_ENCODER_ENCODE 120*b077aed3SPierre Pronchery 121*b077aed3SPierre Pronchery OSSL_FUNC_encoder_import_object OSSL_FUNC_ENCODER_IMPORT_OBJECT 122*b077aed3SPierre Pronchery OSSL_FUNC_encoder_free_object OSSL_FUNC_ENCODER_FREE_OBJECT 123*b077aed3SPierre Pronchery 124*b077aed3SPierre Pronchery=head2 Names and properties 125*b077aed3SPierre Pronchery 126*b077aed3SPierre ProncheryThe name of an implementation should match the type of object it handles. 127*b077aed3SPierre ProncheryFor example, an implementation that encodes an RSA key should be named "RSA". 128*b077aed3SPierre ProncheryLikewise, an implementation that further encodes DER should be named "DER". 129*b077aed3SPierre Pronchery 130*b077aed3SPierre ProncheryProperties can be used to further specify details about an implementation: 131*b077aed3SPierre Pronchery 132*b077aed3SPierre Pronchery=over 4 133*b077aed3SPierre Pronchery 134*b077aed3SPierre Pronchery=item output 135*b077aed3SPierre Pronchery 136*b077aed3SPierre ProncheryThis property is used to specify what type of output the implementation 137*b077aed3SPierre Proncheryproduces. 138*b077aed3SPierre Pronchery 139*b077aed3SPierre ProncheryThis property is I<mandatory>. 140*b077aed3SPierre Pronchery 141*b077aed3SPierre ProncheryOpenSSL providers recognize the following output types: 142*b077aed3SPierre Pronchery 143*b077aed3SPierre Pronchery=over 4 144*b077aed3SPierre Pronchery 145*b077aed3SPierre Pronchery=item text 146*b077aed3SPierre Pronchery 147*b077aed3SPierre ProncheryAn implementation with that output type outputs human readable text, making 148*b077aed3SPierre Proncherythat implementation suitable for C<-text> output in diverse L<openssl(1)> 149*b077aed3SPierre Proncherycommands. 150*b077aed3SPierre Pronchery 151*b077aed3SPierre Pronchery=item pem 152*b077aed3SPierre Pronchery 153*b077aed3SPierre ProncheryAn implementation with that output type outputs PEM formatted data. 154*b077aed3SPierre Pronchery 155*b077aed3SPierre Pronchery=item der 156*b077aed3SPierre Pronchery 157*b077aed3SPierre ProncheryAn implementation with that output type outputs DER formatted data. 158*b077aed3SPierre Pronchery 159*b077aed3SPierre Pronchery=item msblob 160*b077aed3SPierre Pronchery 161*b077aed3SPierre ProncheryAn implementation with that output type outputs MSBLOB formatted data. 162*b077aed3SPierre Pronchery 163*b077aed3SPierre Pronchery=item pvk 164*b077aed3SPierre Pronchery 165*b077aed3SPierre ProncheryAn implementation with that output type outputs PVK formatted data. 166*b077aed3SPierre Pronchery 167*b077aed3SPierre Pronchery=back 168*b077aed3SPierre Pronchery 169*b077aed3SPierre Pronchery=item structure 170*b077aed3SPierre Pronchery 171*b077aed3SPierre ProncheryThis property is used to specify the structure that is used for the encoded 172*b077aed3SPierre Proncheryobject. An example could be C<pkcs8>, to specify explicitly that an object 173*b077aed3SPierre Pronchery(presumably an asymmetric key pair, in this case) will be wrapped in a 174*b077aed3SPierre ProncheryPKCS#8 structure as part of the encoding. 175*b077aed3SPierre Pronchery 176*b077aed3SPierre ProncheryThis property is I<optional>. 177*b077aed3SPierre Pronchery 178*b077aed3SPierre Pronchery=back 179*b077aed3SPierre Pronchery 180*b077aed3SPierre ProncheryThe possible values of both these properties is open ended. A provider may 181*b077aed3SPierre Proncheryvery well specify output types and structures that libcrypto doesn't know 182*b077aed3SPierre Proncheryanything about. 183*b077aed3SPierre Pronchery 184*b077aed3SPierre Pronchery=head2 Subset selections 185*b077aed3SPierre Pronchery 186*b077aed3SPierre ProncherySometimes, an object has more than one subset of data that is interesting to 187*b077aed3SPierre Proncherytreat separately or together. It's possible to specify what subsets are to 188*b077aed3SPierre Proncherybe encoded, with a set of bits I<selection> that are passed in an B<int>. 189*b077aed3SPierre Pronchery 190*b077aed3SPierre ProncheryThis set of bits depend entirely on what kind of provider-side object is 191*b077aed3SPierre Proncherypassed. For example, those bits are assumed to be the same as those used 192*b077aed3SPierre Proncherywith L<provider-keymgmt(7)> (see L<provider-keymgmt(7)/Key Objects>) when 193*b077aed3SPierre Proncherythe object is an asymmetric keypair. 194*b077aed3SPierre Pronchery 195*b077aed3SPierre ProncheryENCODER implementations are free to regard the I<selection> as a set of 196*b077aed3SPierre Proncheryhints, but must do so with care. In the end, the output must make sense, 197*b077aed3SPierre Proncheryand if there's a corresponding decoder, the resulting decoded object must 198*b077aed3SPierre Proncherymatch the original object that was encoded. 199*b077aed3SPierre Pronchery 200*b077aed3SPierre ProncheryOSSL_FUNC_encoder_does_selection() should tell if a particular implementation 201*b077aed3SPierre Proncherysupports any of the combinations given by I<selection>. 202*b077aed3SPierre Pronchery 203*b077aed3SPierre Pronchery=head2 Context functions 204*b077aed3SPierre Pronchery 205*b077aed3SPierre ProncheryOSSL_FUNC_encoder_newctx() returns a context to be used with the rest of 206*b077aed3SPierre Proncherythe functions. 207*b077aed3SPierre Pronchery 208*b077aed3SPierre ProncheryOSSL_FUNC_encoder_freectx() frees the given I<ctx>, if it was created by 209*b077aed3SPierre ProncheryOSSL_FUNC_encoder_newctx(). 210*b077aed3SPierre Pronchery 211*b077aed3SPierre ProncheryOSSL_FUNC_encoder_set_ctx_params() sets context data according to parameters 212*b077aed3SPierre Proncheryfrom I<params> that it recognises. Unrecognised parameters should be 213*b077aed3SPierre Proncheryignored. 214*b077aed3SPierre ProncheryPassing NULL for I<params> should return true. 215*b077aed3SPierre Pronchery 216*b077aed3SPierre ProncheryOSSL_FUNC_encoder_settable_ctx_params() returns a constant L<OSSL_PARAM(3)> 217*b077aed3SPierre Proncheryarray describing the parameters that OSSL_FUNC_encoder_set_ctx_params() 218*b077aed3SPierre Proncherycan handle. 219*b077aed3SPierre Pronchery 220*b077aed3SPierre ProncherySee L<OSSL_PARAM(3)> for further details on the parameters structure used by 221*b077aed3SPierre ProncheryOSSL_FUNC_encoder_set_ctx_params() and OSSL_FUNC_encoder_settable_ctx_params(). 222*b077aed3SPierre Pronchery 223*b077aed3SPierre Pronchery=head2 Import functions 224*b077aed3SPierre Pronchery 225*b077aed3SPierre ProncheryA provider-native object may be associated with a foreign provider, and may 226*b077aed3SPierre Proncherytherefore be unsuitable for direct use with a given ENCODER implementation. 227*b077aed3SPierre ProncheryProvided that the foreign provider's implementation to handle the object has 228*b077aed3SPierre Proncherya function to export that object in L<OSSL_PARAM(3)> array form, the ENCODER 229*b077aed3SPierre Proncheryimplementation should be able to import that array and create a suitable 230*b077aed3SPierre Proncheryobject to be passed to OSSL_FUNC_encoder_encode()'s I<obj_raw>. 231*b077aed3SPierre Pronchery 232*b077aed3SPierre ProncheryOSSL_FUNC_encoder_import_object() should import the subset of I<params> 233*b077aed3SPierre Proncherygiven with I<selection> to create a provider-native object that can be 234*b077aed3SPierre Proncherypassed as I<obj_raw> to OSSL_FUNC_encoder_encode(). 235*b077aed3SPierre Pronchery 236*b077aed3SPierre ProncheryOSSL_FUNC_encoder_free_object() should free the object that was created with 237*b077aed3SPierre ProncheryOSSL_FUNC_encoder_import_object(). 238*b077aed3SPierre Pronchery 239*b077aed3SPierre Pronchery=head2 Encoding functions 240*b077aed3SPierre Pronchery 241*b077aed3SPierre ProncheryOSSL_FUNC_encoder_encode() should take a provider-native object (in 242*b077aed3SPierre ProncheryI<obj_raw>) or an object abstraction (in I<obj_abstract>), and should output 243*b077aed3SPierre Proncherythe object in encoded form to the B<OSSL_CORE_BIO>. The I<selection> bits, 244*b077aed3SPierre Proncheryif relevant, should determine in greater detail what will be output. 245*b077aed3SPierre ProncheryThe encoding functions also take an L<OSSL_PASSPHRASE_CALLBACK(3)> function 246*b077aed3SPierre Proncherypointer along with a pointer to application data I<cbarg>, which should be 247*b077aed3SPierre Proncheryused when a pass phrase prompt is needed. 248*b077aed3SPierre Pronchery 249*b077aed3SPierre Pronchery=head2 Encoder operation parameters 250*b077aed3SPierre Pronchery 251*b077aed3SPierre ProncheryOperation parameters currently recognised by built-in encoders are as 252*b077aed3SPierre Proncheryfollows: 253*b077aed3SPierre Pronchery 254*b077aed3SPierre Pronchery=over 4 255*b077aed3SPierre Pronchery 256*b077aed3SPierre Pronchery=item "cipher" (B<OSSL_ENCODER_PARAM_CIPHER>) <UTF8 string> 257*b077aed3SPierre Pronchery 258*b077aed3SPierre ProncheryThe name of the encryption cipher to be used when generating encrypted 259*b077aed3SPierre Proncheryencoding. This is used when encoding private keys, as well as 260*b077aed3SPierre Proncheryother objects that need protection. 261*b077aed3SPierre Pronchery 262*b077aed3SPierre ProncheryIf this name is invalid for the encoding implementation, the 263*b077aed3SPierre Proncheryimplementation should refuse to perform the encoding, i.e. 264*b077aed3SPierre ProncheryOSSL_FUNC_encoder_encode_data() and OSSL_FUNC_encoder_encode_object() 265*b077aed3SPierre Proncheryshould return an error. 266*b077aed3SPierre Pronchery 267*b077aed3SPierre Pronchery=item "properties" (B<OSSL_ENCODER_PARAM_PROPERTIES>) <UTF8 string> 268*b077aed3SPierre Pronchery 269*b077aed3SPierre ProncheryThe properties to be queried when trying to fetch the algorithm given 270*b077aed3SPierre Proncherywith the "cipher" parameter. 271*b077aed3SPierre ProncheryThis must be given together with the "cipher" parameter to be 272*b077aed3SPierre Proncheryconsidered valid. 273*b077aed3SPierre Pronchery 274*b077aed3SPierre ProncheryThe encoding implementation isn't obligated to use this value. 275*b077aed3SPierre ProncheryHowever, it is recommended that implementations that do not handle 276*b077aed3SPierre Proncheryproperty strings return an error on receiving this parameter unless 277*b077aed3SPierre Proncheryits value NULL or the empty string. 278*b077aed3SPierre Pronchery 279*b077aed3SPierre Pronchery=item "save-parameters" (B<OSSL_ENCODER_PARAM_SAVE_PARAMETERS>) <integer> 280*b077aed3SPierre Pronchery 281*b077aed3SPierre ProncheryIf set to 0 disables saving of key domain parameters. Default is 1. 282*b077aed3SPierre ProncheryIt currently has an effect only on DSA keys. 283*b077aed3SPierre Pronchery 284*b077aed3SPierre Pronchery=back 285*b077aed3SPierre Pronchery 286*b077aed3SPierre ProncheryParameters currently recognised by the built-in pass phrase callback: 287*b077aed3SPierre Pronchery 288*b077aed3SPierre Pronchery=over 4 289*b077aed3SPierre Pronchery 290*b077aed3SPierre Pronchery=item "info" (B<OSSL_PASSPHRASE_PARAM_INFO>) <UTF8 string> 291*b077aed3SPierre Pronchery 292*b077aed3SPierre ProncheryA string of information that will become part of the pass phrase 293*b077aed3SPierre Proncheryprompt. This could be used to give the user information on what kind 294*b077aed3SPierre Proncheryof object it's being prompted for. 295*b077aed3SPierre Pronchery 296*b077aed3SPierre Pronchery=back 297*b077aed3SPierre Pronchery 298*b077aed3SPierre Pronchery=head1 RETURN VALUES 299*b077aed3SPierre Pronchery 300*b077aed3SPierre ProncheryOSSL_FUNC_encoder_newctx() returns a pointer to a context, or NULL on 301*b077aed3SPierre Proncheryfailure. 302*b077aed3SPierre Pronchery 303*b077aed3SPierre ProncheryOSSL_FUNC_encoder_set_ctx_params() returns 1, unless a recognised 304*b077aed3SPierre Proncheryparameter was invalid or caused an error, for which 0 is returned. 305*b077aed3SPierre Pronchery 306*b077aed3SPierre ProncheryOSSL_FUNC_encoder_settable_ctx_params() returns a pointer to an array of 307*b077aed3SPierre Proncheryconstant L<OSSL_PARAM(3)> elements. 308*b077aed3SPierre Pronchery 309*b077aed3SPierre ProncheryOSSL_FUNC_encoder_does_selection() returns 1 if the encoder implementation 310*b077aed3SPierre Proncherysupports any of the I<selection> bits, otherwise 0. 311*b077aed3SPierre Pronchery 312*b077aed3SPierre ProncheryOSSL_FUNC_encoder_encode() returns 1 on success, or 0 on failure. 313*b077aed3SPierre Pronchery 314*b077aed3SPierre Pronchery=head1 SEE ALSO 315*b077aed3SPierre Pronchery 316*b077aed3SPierre ProncheryL<provider(7)> 317*b077aed3SPierre Pronchery 318*b077aed3SPierre Pronchery=head1 HISTORY 319*b077aed3SPierre Pronchery 320*b077aed3SPierre ProncheryThe ENCODER interface was introduced in OpenSSL 3.0. 321*b077aed3SPierre Pronchery 322*b077aed3SPierre Pronchery=head1 COPYRIGHT 323*b077aed3SPierre Pronchery 324*b077aed3SPierre ProncheryCopyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. 325*b077aed3SPierre Pronchery 326*b077aed3SPierre ProncheryLicensed under the Apache License 2.0 (the "License"). You may not use 327*b077aed3SPierre Proncherythis file except in compliance with the License. You can obtain a copy 328*b077aed3SPierre Proncheryin the file LICENSE in the source distribution or at 329*b077aed3SPierre ProncheryL<https://www.openssl.org/source/license.html>. 330*b077aed3SPierre Pronchery 331*b077aed3SPierre Pronchery=cut 332