Coverage Report

Created: 2026-03-31 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/strongswan/src/libstrongswan/crypto/pkcs5.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2012-2013 Tobias Brunner
3
 *
4
 * Copyright (C) secunet Security Networks AG
5
 *
6
 * This program is free software; you can redistribute it and/or modify it
7
 * under the terms of the GNU General Public License as published by the
8
 * Free Software Foundation; either version 2 of the License, or (at your
9
 * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
10
 *
11
 * This program is distributed in the hope that it will be useful, but
12
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14
 * for more details.
15
 */
16
17
#include "pkcs5.h"
18
19
#include <utils/debug.h>
20
#include <asn1/oid.h>
21
#include <asn1/asn1.h>
22
#include <asn1/asn1_parser.h>
23
#include <credentials/containers/pkcs12.h>
24
25
typedef struct private_pkcs5_t private_pkcs5_t;
26
27
/**
28
 * Private data of a pkcs5_t object
29
 */
30
struct private_pkcs5_t {
31
32
  /**
33
   * Implements pkcs5_t.
34
   */
35
  pkcs5_t public;
36
37
  /**
38
   * Salt used during encryption
39
   */
40
  chunk_t salt;
41
42
  /**
43
   * Iterations for key derivation
44
   */
45
  uint64_t iterations;
46
47
  /**
48
   * Encryption algorithm
49
   */
50
  encryption_algorithm_t encr;
51
52
  /**
53
   * Encryption key length
54
   */
55
  size_t keylen;
56
57
  /**
58
   * Crypter
59
   */
60
  crypter_t *crypter;
61
62
63
  /**
64
   * The encryption scheme
65
   */
66
  enum {
67
    PKCS5_SCHEME_PBES1,
68
    PKCS5_SCHEME_PBES2,
69
    PKCS5_SCHEME_PKCS12,
70
  } scheme;
71
72
  /**
73
   * Data used for individual schemes
74
   */
75
  union {
76
    struct {
77
      /**
78
       * Hash algorithm
79
       */
80
      hash_algorithm_t hash;
81
82
      /**
83
       * Hasher
84
       */
85
      hasher_t *hasher;
86
87
    } pbes1;
88
    struct {
89
      /**
90
       * PRF algorithm
91
       */
92
      pseudo_random_function_t prf_alg;
93
94
      /**
95
       * PRF
96
       */
97
      prf_t * prf;
98
99
      /**
100
       * IV
101
       */
102
      chunk_t iv;
103
104
    } pbes2;
105
  } data;
106
};
107
108
/**
109
 * Verify padding of decrypted blob.
110
 * Length of blob is adjusted accordingly.
111
 */
112
static bool verify_padding(crypter_t *crypter, chunk_t *blob)
113
0
{
114
0
  uint8_t padding, count;
115
116
0
  padding = count = blob->ptr[blob->len - 1];
117
118
0
  if (padding > crypter->get_block_size(crypter))
119
0
  {
120
0
    return FALSE;
121
0
  }
122
0
  for (; blob->len && count; --blob->len, --count)
123
0
  {
124
0
    if (blob->ptr[blob->len - 1] != padding)
125
0
    {
126
0
      return FALSE;
127
0
    }
128
0
  }
129
0
  return TRUE;
130
0
}
131
132
/**
133
 * Prototype for key derivation functions.
134
 */
135
typedef bool (*derive_t)(private_pkcs5_t *this, chunk_t password, chunk_t key);
136
137
/**
138
 * Try to decrypt the given data with the given password using the given
139
 * key derivation function. keymat is where the kdf function writes the key
140
 * to, key and iv point to the actual keys and initialization vectors resp.
141
 */
142
static bool decrypt_generic(private_pkcs5_t *this, chunk_t password,
143
              chunk_t data, chunk_t *decrypted, derive_t kdf,
144
              chunk_t keymat, chunk_t key, chunk_t iv)
145
0
{
146
0
  if (!kdf(this, password, keymat))
147
0
  {
148
0
    return FALSE;
149
0
  }
150
0
  if (!this->crypter->set_key(this->crypter, key) ||
151
0
    !this->crypter->decrypt(this->crypter, data, iv, decrypted))
152
0
  {
153
0
    memwipe(keymat.ptr, keymat.len);
154
0
    return FALSE;
155
0
  }
156
0
  memwipe(keymat.ptr, keymat.len);
157
0
  if (verify_padding(this->crypter, decrypted))
158
0
  {
159
0
    return TRUE;
160
0
  }
161
0
  chunk_free(decrypted);
162
0
  return FALSE;
163
0
}
164
165
/**
166
 * KDF as used by PKCS#12
167
 */
168
static bool pkcs12_kdf(private_pkcs5_t *this, chunk_t password, chunk_t keymat)
169
0
{
170
0
  chunk_t key, iv;
171
172
0
  key = chunk_create(keymat.ptr, this->keylen);
173
0
  iv = chunk_create(keymat.ptr + this->keylen, keymat.len - this->keylen);
174
175
0
  return pkcs12_derive_key(this->data.pbes1.hash, password, this->salt,
176
0
               this->iterations, PKCS12_KEY_ENCRYPTION, key) &&
177
0
       pkcs12_derive_key(this->data.pbes1.hash, password, this->salt,
178
0
               this->iterations, PKCS12_KEY_IV, iv);
179
0
}
180
181
/**
182
 * Function F of PBKDF2
183
 */
184
static bool pbkdf2_f(chunk_t block, prf_t *prf, chunk_t seed,
185
           uint64_t iterations)
186
0
{
187
0
  chunk_t u;
188
0
  uint64_t i;
189
190
0
  u = chunk_alloca(prf->get_block_size(prf));
191
0
  if (!prf->get_bytes(prf, seed, u.ptr))
192
0
  {
193
0
    return FALSE;
194
0
  }
195
0
  memcpy(block.ptr, u.ptr, block.len);
196
197
0
  for (i = 1; i < iterations; i++)
198
0
  {
199
0
    if (!prf->get_bytes(prf, u, u.ptr))
200
0
    {
201
0
      return FALSE;
202
0
    }
203
0
    memxor(block.ptr, u.ptr, block.len);
204
0
  }
205
0
  return TRUE;
206
0
}
207
208
/**
209
 * PBKDF2 key derivation function for PBES2, key must be allocated
210
 */
211
static bool pbkdf2(private_pkcs5_t *this, chunk_t password, chunk_t key)
212
0
{
213
0
  prf_t *prf;
214
0
  chunk_t keymat, block, seed;
215
0
  size_t blocks;
216
0
  uint32_t i = 0;
217
218
0
  prf = this->data.pbes2.prf;
219
220
0
  if (!prf->set_key(prf, password))
221
0
  {
222
0
    return FALSE;
223
0
  }
224
225
0
  block.len = prf->get_block_size(prf);
226
0
  blocks = (key.len - 1) / block.len + 1;
227
0
  keymat = chunk_alloca(blocks * block.len);
228
229
0
  seed = chunk_cata("cc", this->salt, chunk_from_thing(i));
230
231
0
  for (; i < blocks; i++)
232
0
  {
233
0
    htoun32(seed.ptr + this->salt.len, i + 1);
234
0
    block.ptr = keymat.ptr + (i * block.len);
235
0
    if (!pbkdf2_f(block, prf, seed, this->iterations))
236
0
    {
237
0
      return FALSE;
238
0
    }
239
0
  }
240
0
  memcpy(key.ptr, keymat.ptr, key.len);
241
0
  return TRUE;
242
0
}
243
244
/**
245
 * PBKDF1 key derivation function for PBES1, key must be allocated
246
 */
247
static bool pbkdf1(private_pkcs5_t *this, chunk_t password, chunk_t key)
248
0
{
249
0
  hasher_t *hasher;
250
0
  chunk_t hash;
251
0
  uint64_t i;
252
253
0
  hasher = this->data.pbes1.hasher;
254
255
0
  hash = chunk_alloca(hasher->get_hash_size(hasher));
256
0
  if (!hasher->get_hash(hasher, password, NULL) ||
257
0
    !hasher->get_hash(hasher, this->salt, hash.ptr))
258
0
  {
259
0
    return FALSE;
260
0
  }
261
262
0
  for (i = 1; i < this->iterations; i++)
263
0
  {
264
0
    if (!hasher->get_hash(hasher, hash, hash.ptr))
265
0
    {
266
0
      return FALSE;
267
0
    }
268
0
  }
269
0
  memcpy(key.ptr, hash.ptr, key.len);
270
0
  return TRUE;
271
0
}
272
273
static bool ensure_crypto_primitives(private_pkcs5_t *this, chunk_t data)
274
0
{
275
0
  if (!this->crypter)
276
0
  {
277
0
    this->crypter = lib->crypto->create_crypter(lib->crypto, this->encr,
278
0
                          this->keylen);
279
0
    if (!this->crypter)
280
0
    {
281
0
      DBG1(DBG_ASN, "  %N encryption algorithm not available",
282
0
         encryption_algorithm_names, this->encr);
283
0
      return FALSE;
284
0
    }
285
0
  }
286
0
  if (data.len % this->crypter->get_block_size(this->crypter))
287
0
  {
288
0
    DBG1(DBG_ASN, "  data size is not a multiple of block size");
289
0
    return FALSE;
290
0
  }
291
0
  switch (this->scheme)
292
0
  {
293
0
    case PKCS5_SCHEME_PBES1:
294
0
    {
295
0
      if (!this->data.pbes1.hasher)
296
0
      {
297
0
        hasher_t *hasher;
298
299
0
        hasher = lib->crypto->create_hasher(lib->crypto,
300
0
                          this->data.pbes1.hash);
301
0
        if (!hasher)
302
0
        {
303
0
          DBG1(DBG_ASN, "  %N hash algorithm not available",
304
0
             hash_algorithm_names, this->data.pbes1.hash);
305
0
          return  FALSE;
306
0
        }
307
0
        if (hasher->get_hash_size(hasher) < this->keylen)
308
0
        {
309
0
          hasher->destroy(hasher);
310
0
          return FALSE;
311
0
        }
312
0
        this->data.pbes1.hasher = hasher;
313
0
      }
314
0
      break;
315
0
    }
316
0
    case PKCS5_SCHEME_PBES2:
317
0
    {
318
0
      if (!this->data.pbes2.prf)
319
0
      {
320
0
        prf_t *prf;
321
322
0
        prf = lib->crypto->create_prf(lib->crypto,
323
0
                        this->data.pbes2.prf_alg);
324
0
        if (!prf)
325
0
        {
326
0
          DBG1(DBG_ASN, "  %N prf algorithm not available",
327
0
             pseudo_random_function_names,
328
0
             this->data.pbes2.prf_alg);
329
0
          return FALSE;
330
0
        }
331
0
        this->data.pbes2.prf = prf;
332
0
      }
333
0
      break;
334
0
    }
335
0
    case PKCS5_SCHEME_PKCS12:
336
0
      break;
337
0
  }
338
0
  return TRUE;
339
0
}
340
341
METHOD(pkcs5_t, decrypt, bool,
342
  private_pkcs5_t *this, chunk_t password, chunk_t data, chunk_t *decrypted)
343
0
{
344
0
  chunk_t keymat, key, iv;
345
0
  derive_t kdf;
346
347
0
  if (!ensure_crypto_primitives(this, data) || !decrypted)
348
0
  {
349
0
    return FALSE;
350
0
  }
351
0
  kdf = pbkdf1;
352
0
  switch (this->scheme)
353
0
  {
354
0
    case PKCS5_SCHEME_PKCS12:
355
0
      kdf = pkcs12_kdf;
356
      /* fall-through */
357
0
    case PKCS5_SCHEME_PBES1:
358
0
      keymat = chunk_alloca(this->keylen +
359
0
                  this->crypter->get_iv_size(this->crypter));
360
0
      key = chunk_create(keymat.ptr, this->keylen);
361
0
      iv = chunk_create(keymat.ptr + this->keylen,
362
0
                keymat.len - this->keylen);
363
0
      break;
364
0
    case PKCS5_SCHEME_PBES2:
365
0
      kdf = pbkdf2;
366
0
      keymat = chunk_alloca(this->keylen);
367
0
      key = keymat;
368
0
      iv = this->data.pbes2.iv;
369
0
      break;
370
0
    default:
371
0
      return FALSE;
372
0
  }
373
0
  return decrypt_generic(this, password, data, decrypted, kdf,
374
0
               keymat, key, iv);
375
0
}
376
377
/**
378
 * ASN.1 definition of a PBEParameter structure
379
 */
380
static const asn1Object_t pbeParameterObjects[] = {
381
  { 0, "PBEParameter",    ASN1_SEQUENCE,    ASN1_NONE }, /* 0 */
382
  { 1,   "salt",        ASN1_OCTET_STRING,  ASN1_BODY }, /* 1 */
383
  { 1,   "iterationCount",  ASN1_INTEGER,   ASN1_BODY }, /* 2 */
384
  { 0, "exit",        ASN1_EOC,     ASN1_EXIT }
385
};
386
0
#define PBEPARAM_SALT         1
387
0
#define PBEPARAM_ITERATION_COUNT    2
388
389
/**
390
 * Parse a PBEParameter structure
391
 */
392
static bool parse_pbes1_params(private_pkcs5_t *this, chunk_t blob, int level0)
393
0
{
394
0
  asn1_parser_t *parser;
395
0
  chunk_t object;
396
0
  int objectID;
397
0
  bool success;
398
399
0
  parser = asn1_parser_create(pbeParameterObjects, blob);
400
0
  parser->set_top_level(parser, level0);
401
402
0
  while (parser->iterate(parser, &objectID, &object))
403
0
  {
404
0
    switch (objectID)
405
0
    {
406
0
      case PBEPARAM_SALT:
407
0
      {
408
0
        this->salt = chunk_clone(object);
409
0
        break;
410
0
      }
411
0
      case PBEPARAM_ITERATION_COUNT:
412
0
      {
413
0
        this->iterations = asn1_parse_integer_uint64(object);
414
0
        break;
415
0
      }
416
0
    }
417
0
  }
418
0
  success = parser->success(parser);
419
0
  parser->destroy(parser);
420
0
  return success;
421
0
}
422
423
/**
424
 * ASN.1 definition of a PBKDF2-params structure
425
 * The salt is actually a CHOICE and could be an AlgorithmIdentifier from
426
 * PBKDF2-SaltSources (but as per RFC 8018 that's for future versions).
427
 * The PRF algorithm is actually defined as DEFAULT and not OPTIONAL, but the
428
 * parser can't handle ASN1_DEF with SEQUENCEs.
429
 */
430
static const asn1Object_t pbkdf2ParamsObjects[] = {
431
  { 0, "PBKDF2-params", ASN1_SEQUENCE,    ASN1_NONE     }, /* 0 */
432
  { 1,   "salt",      ASN1_OCTET_STRING,  ASN1_BODY     }, /* 1 */
433
  { 1,   "iterationCount",ASN1_INTEGER,   ASN1_BODY     }, /* 2 */
434
  { 1,   "keyLength",   ASN1_INTEGER,   ASN1_OPT|ASN1_BODY  }, /* 3 */
435
  { 1,   "end opt",   ASN1_EOC,     ASN1_END      }, /* 4 */
436
  { 1,   "prf",     ASN1_SEQUENCE,    ASN1_OPT|ASN1_RAW }, /* 5 */
437
  { 1,   "end opt",   ASN1_EOC,     ASN1_END      }, /* 6 */
438
  { 0, "exit",      ASN1_EOC,     ASN1_EXIT     }
439
};
440
0
#define PBKDF2_SALT         1
441
0
#define PBKDF2_ITERATION_COUNT    2
442
0
#define PBKDF2_KEYLENGTH      3
443
0
#define PBKDF2_PRF          5
444
445
/**
446
 * Parse a PBKDF2-params structure
447
 */
448
static bool parse_pbkdf2_params(private_pkcs5_t *this, chunk_t blob, int level0)
449
0
{
450
0
  asn1_parser_t *parser;
451
0
  chunk_t object;
452
0
  int objectID;
453
0
  bool success = FALSE;
454
455
0
  parser = asn1_parser_create(pbkdf2ParamsObjects, blob);
456
0
  parser->set_top_level(parser, level0);
457
458
  /* keylen is optional */
459
0
  this->keylen = 0;
460
  /* defaults to id-hmacWithSHA1 */
461
0
  this->data.pbes2.prf_alg = PRF_HMAC_SHA1;
462
463
0
  while (parser->iterate(parser, &objectID, &object))
464
0
  {
465
0
    switch (objectID)
466
0
    {
467
0
      case PBKDF2_SALT:
468
0
      {
469
0
        this->salt = chunk_clone(object);
470
0
        break;
471
0
      }
472
0
      case PBKDF2_ITERATION_COUNT:
473
0
      {
474
0
        this->iterations = asn1_parse_integer_uint64(object);
475
0
        break;
476
0
      }
477
0
      case PBKDF2_KEYLENGTH:
478
0
      {
479
0
        this->keylen = (size_t)asn1_parse_integer_uint64(object);
480
0
        break;
481
0
      }
482
0
      case PBKDF2_PRF:
483
0
      {
484
0
        int oid;
485
486
0
        oid = asn1_parse_algorithmIdentifier(object,
487
0
                    parser->get_level(parser) + 1, NULL);
488
0
        this->data.pbes2.prf_alg = pseudo_random_function_from_oid(oid);
489
0
        if (this->data.pbes2.prf_alg == PRF_UNDEFINED)
490
0
        { /* unsupported PRF algorithm */
491
0
          goto end;
492
0
        }
493
0
        break;
494
0
      }
495
0
    }
496
0
  }
497
0
  success = parser->success(parser);
498
0
end:
499
0
  parser->destroy(parser);
500
0
  return success;
501
0
}
502
503
/**
504
 * ASN.1 definition of a PBES2-params structure
505
 */
506
static const asn1Object_t pbes2ParamsObjects[] = {
507
  { 0, "PBES2-params",    ASN1_SEQUENCE,    ASN1_NONE }, /* 0 */
508
  { 1,   "keyDerivationFunc", ASN1_EOC,     ASN1_RAW  }, /* 1 */
509
  { 1,   "encryptionScheme",  ASN1_EOC,     ASN1_RAW  }, /* 2 */
510
  { 0, "exit",        ASN1_EOC,     ASN1_EXIT }
511
};
512
0
#define PBES2PARAMS_KEY_DERIVATION_FUNC   1
513
0
#define PBES2PARAMS_ENCRYPTION_SCHEME   2
514
515
/**
516
 * Parse a PBES2-params structure
517
 */
518
static bool parse_pbes2_params(private_pkcs5_t *this, chunk_t blob, int level0)
519
0
{
520
0
  asn1_parser_t *parser;
521
0
  chunk_t object, params;
522
0
  size_t keylen;
523
0
  int objectID;
524
0
  bool success = FALSE;
525
526
0
  parser = asn1_parser_create(pbes2ParamsObjects, blob);
527
0
  parser->set_top_level(parser, level0);
528
529
0
  while (parser->iterate(parser, &objectID, &object))
530
0
  {
531
0
    switch (objectID)
532
0
    {
533
0
      case PBES2PARAMS_KEY_DERIVATION_FUNC:
534
0
      {
535
0
        int oid = asn1_parse_algorithmIdentifier(object,
536
0
                  parser->get_level(parser) + 1, &params);
537
0
        if (oid != OID_PBKDF2)
538
0
        { /* unsupported key derivation function */
539
0
          goto end;
540
0
        }
541
0
        if (!parse_pbkdf2_params(this, params,
542
0
                     parser->get_level(parser) + 1))
543
0
        {
544
0
          goto end;
545
0
        }
546
0
        break;
547
0
      }
548
0
      case PBES2PARAMS_ENCRYPTION_SCHEME:
549
0
      {
550
0
        int oid = asn1_parse_algorithmIdentifier(object,
551
0
                  parser->get_level(parser) + 1, &params);
552
0
        this->encr = encryption_algorithm_from_oid(oid, &keylen);
553
0
        if (this->encr == ENCR_UNDEFINED)
554
0
        { /* unsupported encryption scheme */
555
0
          goto end;
556
0
        }
557
        /* prefer encoded key length */
558
0
        this->keylen = this->keylen ?: keylen / 8;
559
0
        if (!this->keylen)
560
0
        { /* set default key length for known algorithms */
561
0
          switch (this->encr)
562
0
          {
563
0
            case ENCR_DES:
564
0
              this->keylen = 8;
565
0
              break;
566
0
            case ENCR_3DES:
567
0
              this->keylen = 24;
568
0
              break;
569
0
            case ENCR_BLOWFISH:
570
0
              this->keylen = 16;
571
0
              break;
572
0
            default:
573
0
              goto end;
574
0
          }
575
0
        }
576
0
        if (!asn1_parse_simple_object(&params, ASN1_OCTET_STRING,
577
0
                  parser->get_level(parser) + 1, "IV"))
578
0
        {
579
0
          goto end;
580
0
        }
581
0
        this->data.pbes2.iv = chunk_clone(params);
582
0
        break;
583
0
      }
584
0
    }
585
0
  }
586
0
  success = parser->success(parser);
587
0
end:
588
0
  parser->destroy(parser);
589
0
  return success;
590
0
}
591
592
METHOD(pkcs5_t, destroy, void,
593
  private_pkcs5_t *this)
594
0
{
595
0
  DESTROY_IF(this->crypter);
596
0
  chunk_free(&this->salt);
597
0
  switch (this->scheme)
598
0
  {
599
0
    case PKCS5_SCHEME_PBES1:
600
0
      DESTROY_IF(this->data.pbes1.hasher);
601
0
      break;
602
0
    case PKCS5_SCHEME_PBES2:
603
0
      DESTROY_IF(this->data.pbes2.prf);
604
0
      chunk_free(&this->data.pbes2.iv);
605
0
      break;
606
0
    case PKCS5_SCHEME_PKCS12:
607
0
      break;
608
0
  }
609
0
  free(this);
610
0
}
611
612
/*
613
 * Described in header
614
 */
615
pkcs5_t *pkcs5_from_algorithmIdentifier(chunk_t blob, int level0)
616
0
{
617
0
  private_pkcs5_t *this;
618
0
  chunk_t params;
619
0
  int oid;
620
621
0
  INIT(this,
622
0
    .public = {
623
0
      .decrypt = _decrypt,
624
0
      .destroy = _destroy,
625
0
    },
626
0
    .scheme = PKCS5_SCHEME_PBES1,
627
0
    .keylen = 8,
628
0
  );
629
630
0
  oid = asn1_parse_algorithmIdentifier(blob, level0, &params);
631
632
0
  switch (oid)
633
0
  {
634
0
    case OID_PBE_MD5_DES_CBC:
635
0
      this->encr = ENCR_DES;
636
0
      this->data.pbes1.hash = HASH_MD5;
637
0
      break;
638
0
    case OID_PBE_SHA1_DES_CBC:
639
0
      this->encr = ENCR_DES;
640
0
      this->data.pbes1.hash = HASH_SHA1;
641
0
      break;
642
0
    case OID_PBE_SHA1_3DES_CBC:
643
0
      this->scheme = PKCS5_SCHEME_PKCS12;
644
0
      this->keylen = 24;
645
0
      this->encr = ENCR_3DES;
646
0
      this->data.pbes1.hash = HASH_SHA1;
647
0
      break;
648
0
    case OID_PBE_SHA1_RC2_CBC_40:
649
0
    case OID_PBE_SHA1_RC2_CBC_128:
650
0
      this->scheme = PKCS5_SCHEME_PKCS12;
651
0
      this->keylen = (oid == OID_PBE_SHA1_RC2_CBC_40) ? 5 : 16;
652
0
      this->encr = ENCR_RC2_CBC;
653
0
      this->data.pbes1.hash = HASH_SHA1;
654
0
      break;
655
0
    case OID_PBES2:
656
0
      this->scheme = PKCS5_SCHEME_PBES2;
657
0
      break;
658
0
    default:
659
      /* encryption scheme not supported */
660
0
      goto failure;
661
0
  }
662
663
0
  switch (this->scheme)
664
0
  {
665
0
    case PKCS5_SCHEME_PBES1:
666
0
    case PKCS5_SCHEME_PKCS12:
667
0
      if (!parse_pbes1_params(this, params, level0))
668
0
      {
669
0
        goto failure;
670
0
      }
671
0
      break;
672
0
    case PKCS5_SCHEME_PBES2:
673
0
      if (!parse_pbes2_params(this, params, level0))
674
0
      {
675
0
        goto failure;
676
0
      }
677
0
      break;
678
0
  }
679
0
  return &this->public;
680
681
0
failure:
682
0
  destroy(this);
683
  return NULL;
684
0
}