root/source4/heimdal/lib/hx509/ks_p12.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. find_attribute
  2. keyBag_parser
  3. ShroudedKeyBag_parser
  4. certBag_parser
  5. parse_safe_content
  6. safeContent_parser
  7. encryptedData_parser
  8. envelopedData_parser
  9. parse_pkcs12_type
  10. p12_init
  11. addBag
  12. store_func
  13. p12_store
  14. p12_free
  15. p12_add
  16. p12_iter_start
  17. p12_iter
  18. p12_iter_end
  19. _hx509_ks_pkcs12_register

   1 /*
   2  * Copyright (c) 2004 - 2007 Kungliga Tekniska Högskolan
   3  * (Royal Institute of Technology, Stockholm, Sweden).
   4  * All rights reserved.
   5  *
   6  * Redistribution and use in source and binary forms, with or without
   7  * modification, are permitted provided that the following conditions
   8  * are met:
   9  *
  10  * 1. Redistributions of source code must retain the above copyright
  11  *    notice, this list of conditions and the following disclaimer.
  12  *
  13  * 2. Redistributions in binary form must reproduce the above copyright
  14  *    notice, this list of conditions and the following disclaimer in the
  15  *    documentation and/or other materials provided with the distribution.
  16  *
  17  * 3. Neither the name of the Institute nor the names of its contributors
  18  *    may be used to endorse or promote products derived from this software
  19  *    without specific prior written permission.
  20  *
  21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
  22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
  25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31  * SUCH DAMAGE.
  32  */
  33 
  34 #include "hx_locl.h"
  35 RCSID("$Id$");
  36 
  37 struct ks_pkcs12 {
  38     hx509_certs certs;
  39     char *fn;
  40 };
  41 
  42 typedef int (*collector_func)(hx509_context,
  43                               struct hx509_collector *,
  44                               const void *, size_t,
  45                               const PKCS12_Attributes *);
  46 
  47 struct type {
  48     const heim_oid * (*oid)(void);
  49     collector_func func;
  50 };
  51 
  52 static void
  53 parse_pkcs12_type(hx509_context, struct hx509_collector *, const heim_oid *,
  54                   const void *, size_t, const PKCS12_Attributes *);
  55 
  56 
  57 static const PKCS12_Attribute *
  58 find_attribute(const PKCS12_Attributes *attrs, const heim_oid *oid)
     /* [<][>][^][v][top][bottom][index][help] */
  59 {
  60     int i;
  61     if (attrs == NULL)
  62         return NULL;
  63     for (i = 0; i < attrs->len; i++)
  64         if (der_heim_oid_cmp(oid, &attrs->val[i].attrId) == 0)
  65             return &attrs->val[i];
  66     return NULL;
  67 }
  68 
  69 static int
  70 keyBag_parser(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
  71               struct hx509_collector *c,
  72               const void *data, size_t length,
  73               const PKCS12_Attributes *attrs)
  74 {
  75     const PKCS12_Attribute *attr;
  76     PKCS8PrivateKeyInfo ki;
  77     const heim_octet_string *os = NULL;
  78     int ret;
  79 
  80     attr = find_attribute(attrs, oid_id_pkcs_9_at_localKeyId());
  81     if (attr)
  82         os = &attr->attrValues;
  83 
  84     ret = decode_PKCS8PrivateKeyInfo(data, length, &ki, NULL);
  85     if (ret)
  86         return ret;
  87 
  88     _hx509_collector_private_key_add(context,
  89                                      c,
  90                                      &ki.privateKeyAlgorithm,
  91                                      NULL,
  92                                      &ki.privateKey,
  93                                      os);
  94     free_PKCS8PrivateKeyInfo(&ki);
  95     return 0;
  96 }
  97 
  98 static int
  99 ShroudedKeyBag_parser(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 100                       struct hx509_collector *c,
 101                       const void *data, size_t length,
 102                       const PKCS12_Attributes *attrs)
 103 {
 104     PKCS8EncryptedPrivateKeyInfo pk;
 105     heim_octet_string content;
 106     int ret;
 107 
 108     memset(&pk, 0, sizeof(pk));
 109 
 110     ret = decode_PKCS8EncryptedPrivateKeyInfo(data, length, &pk, NULL);
 111     if (ret)
 112         return ret;
 113 
 114     ret = _hx509_pbe_decrypt(context,
 115                              _hx509_collector_get_lock(c),
 116                              &pk.encryptionAlgorithm,
 117                              &pk.encryptedData,
 118                              &content);
 119     free_PKCS8EncryptedPrivateKeyInfo(&pk);
 120     if (ret)
 121         return ret;
 122 
 123     ret = keyBag_parser(context, c, content.data, content.length, attrs);
 124     der_free_octet_string(&content);
 125     return ret;
 126 }
 127 
 128 static int
 129 certBag_parser(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 130                struct hx509_collector *c,
 131                const void *data, size_t length,
 132                const PKCS12_Attributes *attrs)
 133 {
 134     heim_octet_string os;
 135     hx509_cert cert;
 136     PKCS12_CertBag cb;
 137     int ret;
 138 
 139     ret = decode_PKCS12_CertBag(data, length, &cb, NULL);
 140     if (ret)
 141         return ret;
 142 
 143     if (der_heim_oid_cmp(oid_id_pkcs_9_at_certTypes_x509(), &cb.certType)) {
 144         free_PKCS12_CertBag(&cb);
 145         return 0;
 146     }
 147 
 148     ret = decode_PKCS12_OctetString(cb.certValue.data,
 149                                     cb.certValue.length,
 150                                     &os,
 151                                     NULL);
 152     free_PKCS12_CertBag(&cb);
 153     if (ret)
 154         return ret;
 155 
 156     ret = hx509_cert_init_data(context, os.data, os.length, &cert);
 157     der_free_octet_string(&os);
 158     if (ret)
 159         return ret;
 160 
 161     ret = _hx509_collector_certs_add(context, c, cert);
 162     if (ret) {
 163         hx509_cert_free(cert);
 164         return ret;
 165     }
 166 
 167     {
 168         const PKCS12_Attribute *attr;
 169         const heim_oid * (*oids[])(void) = {
 170             oid_id_pkcs_9_at_localKeyId, oid_id_pkcs_9_at_friendlyName
 171         };
 172         int i;
 173 
 174         for (i = 0; i < sizeof(oids)/sizeof(oids[0]); i++) {
 175             const heim_oid *oid = (*(oids[i]))();
 176             attr = find_attribute(attrs, oid);
 177             if (attr)
 178                 _hx509_set_cert_attribute(context, cert, oid,
 179                                           &attr->attrValues);
 180         }       
 181     }
 182 
 183     hx509_cert_free(cert);
 184 
 185     return 0;
 186 }
 187 
 188 static int
 189 parse_safe_content(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 190                    struct hx509_collector *c,
 191                    const unsigned char *p, size_t len)
 192 {
 193     PKCS12_SafeContents sc;
 194     int ret, i;
 195 
 196     memset(&sc, 0, sizeof(sc));
 197 
 198     ret = decode_PKCS12_SafeContents(p, len, &sc, NULL);
 199     if (ret)
 200         return ret;
 201 
 202     for (i = 0; i < sc.len ; i++)
 203         parse_pkcs12_type(context,
 204                           c,
 205                           &sc.val[i].bagId,
 206                           sc.val[i].bagValue.data,
 207                           sc.val[i].bagValue.length,
 208                           sc.val[i].bagAttributes);
 209 
 210     free_PKCS12_SafeContents(&sc);
 211     return 0;
 212 }
 213 
 214 static int
 215 safeContent_parser(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 216                    struct hx509_collector *c,
 217                    const void *data, size_t length,
 218                    const PKCS12_Attributes *attrs)
 219 {
 220     heim_octet_string os;
 221     int ret;
 222 
 223     ret = decode_PKCS12_OctetString(data, length, &os, NULL);
 224     if (ret)
 225         return ret;
 226     ret = parse_safe_content(context, c, os.data, os.length);
 227     der_free_octet_string(&os);
 228     return ret;
 229 }
 230 
 231 static int
 232 encryptedData_parser(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 233                      struct hx509_collector *c,
 234                      const void *data, size_t length,
 235                      const PKCS12_Attributes *attrs)
 236 {
 237     heim_octet_string content;
 238     heim_oid contentType;
 239     int ret;
 240                 
 241     memset(&contentType, 0, sizeof(contentType));
 242 
 243     ret = hx509_cms_decrypt_encrypted(context,
 244                                       _hx509_collector_get_lock(c),
 245                                       data, length,
 246                                       &contentType,
 247                                       &content);
 248     if (ret)
 249         return ret;
 250 
 251     if (der_heim_oid_cmp(&contentType, oid_id_pkcs7_data()) == 0)
 252         ret = parse_safe_content(context, c, content.data, content.length);
 253 
 254     der_free_octet_string(&content);
 255     der_free_oid(&contentType);
 256     return ret;
 257 }
 258 
 259 static int
 260 envelopedData_parser(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 261                      struct hx509_collector *c,
 262                      const void *data, size_t length,
 263                      const PKCS12_Attributes *attrs)
 264 {
 265     heim_octet_string content;
 266     heim_oid contentType;
 267     hx509_lock lock;
 268     int ret;
 269                 
 270     memset(&contentType, 0, sizeof(contentType));
 271 
 272     lock = _hx509_collector_get_lock(c);
 273 
 274     ret = hx509_cms_unenvelope(context,
 275                                _hx509_lock_unlock_certs(lock),
 276                                0,
 277                                data, length,
 278                                NULL,
 279                                0,
 280                                &contentType,
 281                                &content);
 282     if (ret) {
 283         hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
 284                                "PKCS12 failed to unenvelope");
 285         return ret;
 286     }
 287 
 288     if (der_heim_oid_cmp(&contentType, oid_id_pkcs7_data()) == 0)
 289         ret = parse_safe_content(context, c, content.data, content.length);
 290 
 291     der_free_octet_string(&content);
 292     der_free_oid(&contentType);
 293 
 294     return ret;
 295 }
 296 
 297 
 298 struct type bagtypes[] = {
 299     { oid_id_pkcs12_keyBag, keyBag_parser },
 300     { oid_id_pkcs12_pkcs8ShroudedKeyBag, ShroudedKeyBag_parser },
 301     { oid_id_pkcs12_certBag, certBag_parser },
 302     { oid_id_pkcs7_data, safeContent_parser },
 303     { oid_id_pkcs7_encryptedData, encryptedData_parser },
 304     { oid_id_pkcs7_envelopedData, envelopedData_parser }
 305 };
 306 
 307 static void
 308 parse_pkcs12_type(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 309                   struct hx509_collector *c,
 310                   const heim_oid *oid,
 311                   const void *data, size_t length,
 312                   const PKCS12_Attributes *attrs)
 313 {
 314     int i;
 315 
 316     for (i = 0; i < sizeof(bagtypes)/sizeof(bagtypes[0]); i++)
 317         if (der_heim_oid_cmp((*bagtypes[i].oid)(), oid) == 0)
 318             (*bagtypes[i].func)(context, c, data, length, attrs);
 319 }
 320 
 321 static int
 322 p12_init(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 323          hx509_certs certs, void **data, int flags,
 324          const char *residue, hx509_lock lock)
 325 {
 326     struct ks_pkcs12 *p12;
 327     size_t len;
 328     void *buf;
 329     PKCS12_PFX pfx;
 330     PKCS12_AuthenticatedSafe as;
 331     int ret, i;
 332     struct hx509_collector *c;
 333 
 334     *data = NULL;
 335 
 336     if (lock == NULL)
 337         lock = _hx509_empty_lock;
 338 
 339     ret = _hx509_collector_alloc(context, lock, &c);
 340     if (ret)
 341         return ret;
 342 
 343     p12 = calloc(1, sizeof(*p12));
 344     if (p12 == NULL) {
 345         ret = ENOMEM;
 346         hx509_set_error_string(context, 0, ret, "out of memory");
 347         goto out;
 348     }
 349 
 350     p12->fn = strdup(residue);
 351     if (p12->fn == NULL) {
 352         ret = ENOMEM;
 353         hx509_set_error_string(context, 0, ret, "out of memory");
 354         goto out;
 355     }
 356 
 357     if (flags & HX509_CERTS_CREATE) {
 358         ret = hx509_certs_init(context, "MEMORY:ks-file-create",
 359                                0, lock, &p12->certs);
 360         if (ret == 0)
 361             *data = p12;
 362         goto out;
 363     }
 364 
 365     ret = rk_undumpdata(residue, &buf, &len);
 366     if (ret) {
 367         hx509_clear_error_string(context);
 368         goto out;
 369     }
 370 
 371     ret = decode_PKCS12_PFX(buf, len, &pfx, NULL);
 372     rk_xfree(buf);
 373     if (ret) {
 374         hx509_set_error_string(context, 0, ret,
 375                                "Failed to decode the PFX in %s", residue);
 376         goto out;
 377     }
 378 
 379     if (der_heim_oid_cmp(&pfx.authSafe.contentType, oid_id_pkcs7_data()) != 0) {
 380         free_PKCS12_PFX(&pfx);
 381         ret = EINVAL;
 382         hx509_set_error_string(context, 0, ret,
 383                                "PKCS PFX isn't a pkcs7-data container");
 384         goto out;
 385     }
 386 
 387     if (pfx.authSafe.content == NULL) {
 388         free_PKCS12_PFX(&pfx);
 389         ret = EINVAL;
 390         hx509_set_error_string(context, 0, ret,
 391                                "PKCS PFX missing data");
 392         goto out;
 393     }
 394 
 395     {
 396         heim_octet_string asdata;
 397 
 398         ret = decode_PKCS12_OctetString(pfx.authSafe.content->data,
 399                                         pfx.authSafe.content->length,
 400                                         &asdata,
 401                                         NULL);
 402         free_PKCS12_PFX(&pfx);
 403         if (ret) {
 404             hx509_clear_error_string(context);
 405             goto out;
 406         }
 407         ret = decode_PKCS12_AuthenticatedSafe(asdata.data,
 408                                               asdata.length,
 409                                               &as,
 410                                               NULL);
 411         der_free_octet_string(&asdata);
 412         if (ret) {
 413             hx509_clear_error_string(context);
 414             goto out;
 415         }
 416     }
 417 
 418     for (i = 0; i < as.len; i++)
 419         parse_pkcs12_type(context,
 420                           c,
 421                           &as.val[i].contentType,
 422                           as.val[i].content->data,
 423                           as.val[i].content->length,
 424                           NULL);
 425 
 426     free_PKCS12_AuthenticatedSafe(&as);
 427 
 428     ret = _hx509_collector_collect_certs(context, c, &p12->certs);
 429     if (ret == 0)
 430         *data = p12;
 431 
 432 out:
 433     _hx509_collector_free(c);
 434 
 435     if (ret && p12) {
 436         if (p12->fn)
 437             free(p12->fn);
 438         if (p12->certs)
 439             hx509_certs_free(&p12->certs);
 440         free(p12);
 441     }
 442 
 443     return ret;
 444 }
 445 
 446 static int
 447 addBag(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 448        PKCS12_AuthenticatedSafe *as,
 449        const heim_oid *oid,
 450        void *data,
 451        size_t length)
 452 {
 453     void *ptr;
 454     int ret;
 455 
 456     ptr = realloc(as->val, sizeof(as->val[0]) * (as->len + 1));
 457     if (ptr == NULL) {
 458         hx509_set_error_string(context, 0, ENOMEM, "out of memory");
 459         return ENOMEM;
 460     }
 461     as->val = ptr;
 462 
 463     ret = der_copy_oid(oid, &as->val[as->len].contentType);
 464     if (ret) {
 465         hx509_set_error_string(context, 0, ret, "out of memory");
 466         return ret;
 467     }
 468 
 469     as->val[as->len].content = calloc(1, sizeof(*as->val[0].content));
 470     if (as->val[as->len].content == NULL) {
 471         der_free_oid(&as->val[as->len].contentType);
 472         hx509_set_error_string(context, 0, ENOMEM, "malloc out of memory");
 473         return ENOMEM;
 474     }
 475 
 476     as->val[as->len].content->data = data;
 477     as->val[as->len].content->length = length;
 478 
 479     as->len++;
 480 
 481     return 0;
 482 }
 483 
 484 static int
 485 store_func(hx509_context context, void *ctx, hx509_cert c)
     /* [<][>][^][v][top][bottom][index][help] */
 486 {
 487     PKCS12_AuthenticatedSafe *as = ctx;
 488     PKCS12_OctetString os;
 489     PKCS12_CertBag cb;
 490     size_t size;
 491     int ret;
 492 
 493     memset(&os, 0, sizeof(os));
 494     memset(&cb, 0, sizeof(cb));
 495 
 496     os.data = NULL;
 497     os.length = 0;
 498 
 499     ret = hx509_cert_binary(context, c, &os);
 500     if (ret)
 501         return ret;
 502 
 503     ASN1_MALLOC_ENCODE(PKCS12_OctetString,
 504                        cb.certValue.data,cb.certValue.length,
 505                        &os, &size, ret);
 506     free(os.data);
 507     if (ret)
 508         goto out;
 509     ret = der_copy_oid(oid_id_pkcs_9_at_certTypes_x509(), &cb.certType);
 510     if (ret) {
 511         free_PKCS12_CertBag(&cb);
 512         goto out;
 513     }
 514     ASN1_MALLOC_ENCODE(PKCS12_CertBag, os.data, os.length,
 515                        &cb, &size, ret);
 516     free_PKCS12_CertBag(&cb);
 517     if (ret)
 518         goto out;
 519 
 520     ret = addBag(context, as, oid_id_pkcs12_certBag(), os.data, os.length);
 521 
 522     if (_hx509_cert_private_key_exportable(c)) {
 523         hx509_private_key key = _hx509_cert_private_key(c);
 524         PKCS8PrivateKeyInfo pki;
 525 
 526         memset(&pki, 0, sizeof(pki));
 527 
 528         ret = der_parse_hex_heim_integer("00", &pki.version);
 529         if (ret)
 530             return ret;
 531         ret = _hx509_private_key_oid(context, key,
 532                                      &pki.privateKeyAlgorithm.algorithm);
 533         if (ret) {
 534             free_PKCS8PrivateKeyInfo(&pki);
 535             return ret;
 536         }
 537         ret = _hx509_private_key_export(context,
 538                                         _hx509_cert_private_key(c),
 539                                         &pki.privateKey);
 540         if (ret) {
 541             free_PKCS8PrivateKeyInfo(&pki);
 542             return ret;
 543         }
 544         /* set attribute, oid_id_pkcs_9_at_localKeyId() */
 545 
 546         ASN1_MALLOC_ENCODE(PKCS8PrivateKeyInfo, os.data, os.length,
 547                            &pki, &size, ret);
 548         free_PKCS8PrivateKeyInfo(&pki);
 549         if (ret)
 550             return ret;
 551 
 552         ret = addBag(context, as, oid_id_pkcs12_keyBag(), os.data, os.length);
 553         if (ret)
 554             return ret;
 555     }
 556 
 557 out:
 558     return ret;
 559 }
 560 
 561 static int
 562 p12_store(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 563           hx509_certs certs, void *data, int flags, hx509_lock lock)
 564 {
 565     struct ks_pkcs12 *p12 = data;
 566     PKCS12_PFX pfx;
 567     PKCS12_AuthenticatedSafe as;
 568     PKCS12_OctetString asdata;
 569     size_t size;
 570     int ret;
 571 
 572     memset(&as, 0, sizeof(as));
 573     memset(&pfx, 0, sizeof(pfx));
 574 
 575     ret = hx509_certs_iter(context, p12->certs, store_func, &as);
 576     if (ret)
 577         goto out;
 578 
 579     ASN1_MALLOC_ENCODE(PKCS12_AuthenticatedSafe, asdata.data, asdata.length,
 580                        &as, &size, ret);
 581     free_PKCS12_AuthenticatedSafe(&as);
 582     if (ret)
 583         return ret;
 584                 
 585     ret = der_parse_hex_heim_integer("03", &pfx.version);
 586     if (ret) {
 587         free(asdata.data);
 588         goto out;
 589     }
 590 
 591     pfx.authSafe.content = calloc(1, sizeof(*pfx.authSafe.content));
 592 
 593     ASN1_MALLOC_ENCODE(PKCS12_OctetString,
 594                        pfx.authSafe.content->data,
 595                        pfx.authSafe.content->length,
 596                        &asdata, &size, ret);
 597     free(asdata.data);
 598     if (ret)
 599         goto out;
 600 
 601     ret = der_copy_oid(oid_id_pkcs7_data(), &pfx.authSafe.contentType);
 602     if (ret)
 603         goto out;
 604 
 605     ASN1_MALLOC_ENCODE(PKCS12_PFX, asdata.data, asdata.length,
 606                        &pfx, &size, ret);
 607     if (ret)
 608         goto out;
 609 
 610 #if 0
 611     const struct _hx509_password *pw;
 612 
 613     pw = _hx509_lock_get_passwords(lock);
 614     if (pw != NULL) {
 615         pfx.macData = calloc(1, sizeof(*pfx.macData));
 616         if (pfx.macData == NULL) {
 617             ret = ENOMEM;
 618             hx509_set_error_string(context, 0, ret, "malloc out of memory");
 619             return ret;
 620         }
 621         if (pfx.macData == NULL) {
 622             free(asdata.data);
 623             goto out;
 624         }
 625     }
 626     ret = calculate_hash(&aspath, pw, pfx.macData);
 627 #endif
 628 
 629     rk_dumpdata(p12->fn, asdata.data, asdata.length);
 630     free(asdata.data);
 631 
 632 out:
 633     free_PKCS12_AuthenticatedSafe(&as);
 634     free_PKCS12_PFX(&pfx);
 635 
 636     return ret;
 637 }
 638 
 639 
 640 static int
 641 p12_free(hx509_certs certs, void *data)
     /* [<][>][^][v][top][bottom][index][help] */
 642 {
 643     struct ks_pkcs12 *p12 = data;
 644     hx509_certs_free(&p12->certs);
 645     free(p12->fn);
 646     free(p12);
 647     return 0;
 648 }
 649 
 650 static int
 651 p12_add(hx509_context context, hx509_certs certs, void *data, hx509_cert c)
     /* [<][>][^][v][top][bottom][index][help] */
 652 {
 653     struct ks_pkcs12 *p12 = data;
 654     return hx509_certs_add(context, p12->certs, c);
 655 }
 656 
 657 static int
 658 p12_iter_start(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 659                hx509_certs certs,
 660                void *data,
 661                void **cursor)
 662 {
 663     struct ks_pkcs12 *p12 = data;
 664     return hx509_certs_start_seq(context, p12->certs, cursor);
 665 }
 666 
 667 static int
 668 p12_iter(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 669          hx509_certs certs,
 670          void *data,
 671          void *cursor,
 672          hx509_cert *cert)
 673 {
 674     struct ks_pkcs12 *p12 = data;
 675     return hx509_certs_next_cert(context, p12->certs, cursor, cert);
 676 }
 677 
 678 static int
 679 p12_iter_end(hx509_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 680              hx509_certs certs,
 681              void *data,
 682              void *cursor)
 683 {
 684     struct ks_pkcs12 *p12 = data;
 685     return hx509_certs_end_seq(context, p12->certs, cursor);
 686 }
 687 
 688 static struct hx509_keyset_ops keyset_pkcs12 = {
 689     "PKCS12",
 690     0,
 691     p12_init,
 692     p12_store,
 693     p12_free,
 694     p12_add,
 695     NULL,
 696     p12_iter_start,
 697     p12_iter,
 698     p12_iter_end
 699 };
 700 
 701 void
 702 _hx509_ks_pkcs12_register(hx509_context context)
     /* [<][>][^][v][top][bottom][index][help] */
 703 {
 704     _hx509_ks_register(context, &keyset_pkcs12);
 705 }

/* [<][>][^][v][top][bottom][index][help] */