uboot/lib/crypto/pkcs7_parser.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/* PKCS#7 parser
   3 *
   4 * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
   5 * Written by David Howells (dhowells@redhat.com)
   6 */
   7
   8#define pr_fmt(fmt) "PKCS7: "fmt
   9#ifdef __UBOOT__
  10#include <log.h>
  11#include <dm/devres.h>
  12#include <linux/bitops.h>
  13#include <linux/compat.h>
  14#endif
  15#include <linux/kernel.h>
  16#ifndef __UBOOT__
  17#include <linux/module.h>
  18#include <linux/export.h>
  19#include <linux/slab.h>
  20#endif
  21#include <linux/err.h>
  22#include <linux/oid_registry.h>
  23#include <crypto/public_key.h>
  24#ifdef __UBOOT__
  25#include <crypto/pkcs7_parser.h>
  26#else
  27#include "pkcs7_parser.h"
  28#endif
  29#include "pkcs7.asn1.h"
  30
  31MODULE_DESCRIPTION("PKCS#7 parser");
  32MODULE_AUTHOR("Red Hat, Inc.");
  33MODULE_LICENSE("GPL");
  34
  35struct pkcs7_parse_context {
  36        struct pkcs7_message    *msg;           /* Message being constructed */
  37        struct pkcs7_signed_info *sinfo;        /* SignedInfo being constructed */
  38        struct pkcs7_signed_info **ppsinfo;
  39        struct x509_certificate *certs;         /* Certificate cache */
  40        struct x509_certificate **ppcerts;
  41        unsigned long   data;                   /* Start of data */
  42        enum OID        last_oid;               /* Last OID encountered */
  43        unsigned        x509_index;
  44        unsigned        sinfo_index;
  45        const void      *raw_serial;
  46        unsigned        raw_serial_size;
  47        unsigned        raw_issuer_size;
  48        const void      *raw_issuer;
  49        const void      *raw_skid;
  50        unsigned        raw_skid_size;
  51        bool            expect_skid;
  52};
  53
  54/*
  55 * Free a signed information block.
  56 */
  57static void pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo)
  58{
  59        if (sinfo) {
  60                public_key_signature_free(sinfo->sig);
  61                kfree(sinfo);
  62        }
  63}
  64
  65/**
  66 * pkcs7_free_message - Free a PKCS#7 message
  67 * @pkcs7: The PKCS#7 message to free
  68 */
  69void pkcs7_free_message(struct pkcs7_message *pkcs7)
  70{
  71        struct x509_certificate *cert;
  72        struct pkcs7_signed_info *sinfo;
  73
  74        if (pkcs7) {
  75                while (pkcs7->certs) {
  76                        cert = pkcs7->certs;
  77                        pkcs7->certs = cert->next;
  78                        x509_free_certificate(cert);
  79                }
  80                while (pkcs7->crl) {
  81                        cert = pkcs7->crl;
  82                        pkcs7->crl = cert->next;
  83                        x509_free_certificate(cert);
  84                }
  85                while (pkcs7->signed_infos) {
  86                        sinfo = pkcs7->signed_infos;
  87                        pkcs7->signed_infos = sinfo->next;
  88                        pkcs7_free_signed_info(sinfo);
  89                }
  90                kfree(pkcs7);
  91        }
  92}
  93EXPORT_SYMBOL_GPL(pkcs7_free_message);
  94
  95/*
  96 * Check authenticatedAttributes are provided or not provided consistently.
  97 */
  98static int pkcs7_check_authattrs(struct pkcs7_message *msg)
  99{
 100        struct pkcs7_signed_info *sinfo;
 101        bool want = false;
 102
 103        sinfo = msg->signed_infos;
 104        if (!sinfo)
 105                goto inconsistent;
 106
 107        if (sinfo->authattrs) {
 108                want = true;
 109                msg->have_authattrs = true;
 110        }
 111
 112        for (sinfo = sinfo->next; sinfo; sinfo = sinfo->next)
 113                if (!!sinfo->authattrs != want)
 114                        goto inconsistent;
 115        return 0;
 116
 117inconsistent:
 118        pr_warn("Inconsistently supplied authAttrs\n");
 119        return -EINVAL;
 120}
 121
 122/**
 123 * pkcs7_parse_message - Parse a PKCS#7 message
 124 * @data: The raw binary ASN.1 encoded message to be parsed
 125 * @datalen: The size of the encoded message
 126 */
 127struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen)
 128{
 129        struct pkcs7_parse_context *ctx;
 130        struct pkcs7_message *msg = ERR_PTR(-ENOMEM);
 131        int ret;
 132
 133        ctx = kzalloc(sizeof(struct pkcs7_parse_context), GFP_KERNEL);
 134        if (!ctx)
 135                goto out_no_ctx;
 136        ctx->msg = kzalloc(sizeof(struct pkcs7_message), GFP_KERNEL);
 137        if (!ctx->msg)
 138                goto out_no_msg;
 139        ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
 140        if (!ctx->sinfo)
 141                goto out_no_sinfo;
 142        ctx->sinfo->sig = kzalloc(sizeof(struct public_key_signature),
 143                                  GFP_KERNEL);
 144        if (!ctx->sinfo->sig)
 145                goto out_no_sig;
 146
 147        ctx->data = (unsigned long)data;
 148        ctx->ppcerts = &ctx->certs;
 149        ctx->ppsinfo = &ctx->msg->signed_infos;
 150
 151        /* Attempt to decode the signature */
 152        ret = asn1_ber_decoder(&pkcs7_decoder, ctx, data, datalen);
 153        if (ret < 0) {
 154                msg = ERR_PTR(ret);
 155                goto out;
 156        }
 157
 158        ret = pkcs7_check_authattrs(ctx->msg);
 159        if (ret < 0) {
 160                msg = ERR_PTR(ret);
 161                goto out;
 162        }
 163
 164        msg = ctx->msg;
 165        ctx->msg = NULL;
 166
 167out:
 168        while (ctx->certs) {
 169                struct x509_certificate *cert = ctx->certs;
 170                ctx->certs = cert->next;
 171                x509_free_certificate(cert);
 172        }
 173out_no_sig:
 174        pkcs7_free_signed_info(ctx->sinfo);
 175out_no_sinfo:
 176        pkcs7_free_message(ctx->msg);
 177out_no_msg:
 178        kfree(ctx);
 179out_no_ctx:
 180        return msg;
 181}
 182EXPORT_SYMBOL_GPL(pkcs7_parse_message);
 183
 184/**
 185 * pkcs7_get_content_data - Get access to the PKCS#7 content
 186 * @pkcs7: The preparsed PKCS#7 message to access
 187 * @_data: Place to return a pointer to the data
 188 * @_data_len: Place to return the data length
 189 * @_headerlen: Size of ASN.1 header not included in _data
 190 *
 191 * Get access to the data content of the PKCS#7 message.  The size of the
 192 * header of the ASN.1 object that contains it is also provided and can be used
 193 * to adjust *_data and *_data_len to get the entire object.
 194 *
 195 * Returns -ENODATA if the data object was missing from the message.
 196 */
 197int pkcs7_get_content_data(const struct pkcs7_message *pkcs7,
 198                           const void **_data, size_t *_data_len,
 199                           size_t *_headerlen)
 200{
 201        if (!pkcs7->data)
 202                return -ENODATA;
 203
 204        *_data = pkcs7->data;
 205        *_data_len = pkcs7->data_len;
 206        if (_headerlen)
 207                *_headerlen = pkcs7->data_hdrlen;
 208        return 0;
 209}
 210EXPORT_SYMBOL_GPL(pkcs7_get_content_data);
 211
 212/*
 213 * Note an OID when we find one for later processing when we know how
 214 * to interpret it.
 215 */
 216int pkcs7_note_OID(void *context, size_t hdrlen,
 217                   unsigned char tag,
 218                   const void *value, size_t vlen)
 219{
 220        struct pkcs7_parse_context *ctx = context;
 221
 222        ctx->last_oid = look_up_OID(value, vlen);
 223        if (ctx->last_oid == OID__NR) {
 224                char buffer[50];
 225                sprint_oid(value, vlen, buffer, sizeof(buffer));
 226                printk("PKCS7: Unknown OID: [%lu] %s\n",
 227                       (unsigned long)value - ctx->data, buffer);
 228        }
 229        return 0;
 230}
 231
 232/*
 233 * Note the digest algorithm for the signature.
 234 */
 235int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen,
 236                               unsigned char tag,
 237                               const void *value, size_t vlen)
 238{
 239        struct pkcs7_parse_context *ctx = context;
 240
 241        switch (ctx->last_oid) {
 242        case OID_md4:
 243                ctx->sinfo->sig->hash_algo = "md4";
 244                break;
 245        case OID_md5:
 246                ctx->sinfo->sig->hash_algo = "md5";
 247                break;
 248        case OID_sha1:
 249                ctx->sinfo->sig->hash_algo = "sha1";
 250                break;
 251        case OID_sha256:
 252                ctx->sinfo->sig->hash_algo = "sha256";
 253                break;
 254        case OID_sha384:
 255                ctx->sinfo->sig->hash_algo = "sha384";
 256                break;
 257        case OID_sha512:
 258                ctx->sinfo->sig->hash_algo = "sha512";
 259                break;
 260        case OID_sha224:
 261                ctx->sinfo->sig->hash_algo = "sha224";
 262                break;
 263        default:
 264                printk("Unsupported digest algo: %u\n", ctx->last_oid);
 265                return -ENOPKG;
 266        }
 267        return 0;
 268}
 269
 270/*
 271 * Note the public key algorithm for the signature.
 272 */
 273int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen,
 274                             unsigned char tag,
 275                             const void *value, size_t vlen)
 276{
 277        struct pkcs7_parse_context *ctx = context;
 278
 279        switch (ctx->last_oid) {
 280        case OID_rsaEncryption:
 281                ctx->sinfo->sig->pkey_algo = "rsa";
 282                ctx->sinfo->sig->encoding = "pkcs1";
 283                break;
 284        default:
 285                printk("Unsupported pkey algo: %u\n", ctx->last_oid);
 286                return -ENOPKG;
 287        }
 288        return 0;
 289}
 290
 291/*
 292 * We only support signed data [RFC2315 sec 9].
 293 */
 294int pkcs7_check_content_type(void *context, size_t hdrlen,
 295                             unsigned char tag,
 296                             const void *value, size_t vlen)
 297{
 298        struct pkcs7_parse_context *ctx = context;
 299
 300        if (ctx->last_oid != OID_signed_data) {
 301                pr_warn("Only support pkcs7_signedData type\n");
 302                return -EINVAL;
 303        }
 304
 305        return 0;
 306}
 307
 308/*
 309 * Note the SignedData version
 310 */
 311int pkcs7_note_signeddata_version(void *context, size_t hdrlen,
 312                                  unsigned char tag,
 313                                  const void *value, size_t vlen)
 314{
 315        struct pkcs7_parse_context *ctx = context;
 316        unsigned version;
 317
 318        if (vlen != 1)
 319                goto unsupported;
 320
 321        ctx->msg->version = version = *(const u8 *)value;
 322        switch (version) {
 323        case 1:
 324                /* PKCS#7 SignedData [RFC2315 sec 9.1]
 325                 * CMS ver 1 SignedData [RFC5652 sec 5.1]
 326                 */
 327                break;
 328        case 3:
 329                /* CMS ver 3 SignedData [RFC2315 sec 5.1] */
 330                break;
 331        default:
 332                goto unsupported;
 333        }
 334
 335        return 0;
 336
 337unsupported:
 338        pr_warn("Unsupported SignedData version\n");
 339        return -EINVAL;
 340}
 341
 342/*
 343 * Note the SignerInfo version
 344 */
 345int pkcs7_note_signerinfo_version(void *context, size_t hdrlen,
 346                                  unsigned char tag,
 347                                  const void *value, size_t vlen)
 348{
 349        struct pkcs7_parse_context *ctx = context;
 350        unsigned version;
 351
 352        if (vlen != 1)
 353                goto unsupported;
 354
 355        version = *(const u8 *)value;
 356        switch (version) {
 357        case 1:
 358                /* PKCS#7 SignerInfo [RFC2315 sec 9.2]
 359                 * CMS ver 1 SignerInfo [RFC5652 sec 5.3]
 360                 */
 361                if (ctx->msg->version != 1)
 362                        goto version_mismatch;
 363                ctx->expect_skid = false;
 364                break;
 365        case 3:
 366                /* CMS ver 3 SignerInfo [RFC2315 sec 5.3] */
 367                if (ctx->msg->version == 1)
 368                        goto version_mismatch;
 369                ctx->expect_skid = true;
 370                break;
 371        default:
 372                goto unsupported;
 373        }
 374
 375        return 0;
 376
 377unsupported:
 378        pr_warn("Unsupported SignerInfo version\n");
 379        return -EINVAL;
 380version_mismatch:
 381        pr_warn("SignedData-SignerInfo version mismatch\n");
 382        return -EBADMSG;
 383}
 384
 385/*
 386 * Extract a certificate and store it in the context.
 387 */
 388int pkcs7_extract_cert(void *context, size_t hdrlen,
 389                       unsigned char tag,
 390                       const void *value, size_t vlen)
 391{
 392        struct pkcs7_parse_context *ctx = context;
 393        struct x509_certificate *x509;
 394
 395        if (tag != ((ASN1_UNIV << 6) | ASN1_CONS_BIT | ASN1_SEQ)) {
 396                pr_debug("Cert began with tag %02x at %lu\n",
 397                         tag, (unsigned long)ctx - ctx->data);
 398                return -EBADMSG;
 399        }
 400
 401        /* We have to correct for the header so that the X.509 parser can start
 402         * from the beginning.  Note that since X.509 stipulates DER, there
 403         * probably shouldn't be an EOC trailer - but it is in PKCS#7 (which
 404         * stipulates BER).
 405         */
 406        value -= hdrlen;
 407        vlen += hdrlen;
 408
 409        if (((u8*)value)[1] == 0x80)
 410                vlen += 2; /* Indefinite length - there should be an EOC */
 411
 412        x509 = x509_cert_parse(value, vlen);
 413        if (IS_ERR(x509))
 414                return PTR_ERR(x509);
 415
 416        x509->index = ++ctx->x509_index;
 417        pr_debug("Got cert %u for %s\n", x509->index, x509->subject);
 418        pr_debug("- fingerprint %*phN\n", x509->id->len, x509->id->data);
 419
 420        *ctx->ppcerts = x509;
 421        ctx->ppcerts = &x509->next;
 422        return 0;
 423}
 424
 425/*
 426 * Save the certificate list
 427 */
 428int pkcs7_note_certificate_list(void *context, size_t hdrlen,
 429                                unsigned char tag,
 430                                const void *value, size_t vlen)
 431{
 432        struct pkcs7_parse_context *ctx = context;
 433
 434        pr_devel("Got cert list (%02x)\n", tag);
 435
 436        *ctx->ppcerts = ctx->msg->certs;
 437        ctx->msg->certs = ctx->certs;
 438        ctx->certs = NULL;
 439        ctx->ppcerts = &ctx->certs;
 440        return 0;
 441}
 442
 443/*
 444 * Note the content type.
 445 */
 446int pkcs7_note_content(void *context, size_t hdrlen,
 447                       unsigned char tag,
 448                       const void *value, size_t vlen)
 449{
 450        struct pkcs7_parse_context *ctx = context;
 451
 452        if (ctx->last_oid != OID_data &&
 453            ctx->last_oid != OID_msIndirectData) {
 454                pr_warn("Unsupported data type %d\n", ctx->last_oid);
 455                return -EINVAL;
 456        }
 457
 458        ctx->msg->data_type = ctx->last_oid;
 459        return 0;
 460}
 461
 462/*
 463 * Extract the data from the message and store that and its content type OID in
 464 * the context.
 465 */
 466int pkcs7_note_data(void *context, size_t hdrlen,
 467                    unsigned char tag,
 468                    const void *value, size_t vlen)
 469{
 470        struct pkcs7_parse_context *ctx = context;
 471
 472        pr_debug("Got data\n");
 473
 474        ctx->msg->data = value;
 475        ctx->msg->data_len = vlen;
 476        ctx->msg->data_hdrlen = hdrlen;
 477        return 0;
 478}
 479
 480/*
 481 * Parse authenticated attributes.
 482 */
 483int pkcs7_sig_note_authenticated_attr(void *context, size_t hdrlen,
 484                                      unsigned char tag,
 485                                      const void *value, size_t vlen)
 486{
 487        struct pkcs7_parse_context *ctx = context;
 488        struct pkcs7_signed_info *sinfo = ctx->sinfo;
 489        enum OID content_type;
 490
 491        pr_devel("AuthAttr: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value);
 492
 493        switch (ctx->last_oid) {
 494        case OID_contentType:
 495                if (__test_and_set_bit(sinfo_has_content_type, &sinfo->aa_set))
 496                        goto repeated;
 497                content_type = look_up_OID(value, vlen);
 498                if (content_type != ctx->msg->data_type) {
 499                        pr_warn("Mismatch between global data type (%d) and sinfo %u (%d)\n",
 500                                ctx->msg->data_type, sinfo->index,
 501                                content_type);
 502                        return -EBADMSG;
 503                }
 504                return 0;
 505
 506        case OID_signingTime:
 507                if (__test_and_set_bit(sinfo_has_signing_time, &sinfo->aa_set))
 508                        goto repeated;
 509                /* Should we check that the signing time is consistent
 510                 * with the signer's X.509 cert?
 511                 */
 512                return x509_decode_time(&sinfo->signing_time,
 513                                        hdrlen, tag, value, vlen);
 514
 515        case OID_messageDigest:
 516                if (__test_and_set_bit(sinfo_has_message_digest, &sinfo->aa_set))
 517                        goto repeated;
 518                if (tag != ASN1_OTS)
 519                        return -EBADMSG;
 520                sinfo->msgdigest = value;
 521                sinfo->msgdigest_len = vlen;
 522                return 0;
 523
 524        case OID_smimeCapabilites:
 525                if (__test_and_set_bit(sinfo_has_smime_caps, &sinfo->aa_set))
 526                        goto repeated;
 527#ifdef __UBOOT__ /* OID_data is needed for authenticated UEFI variables */
 528                if (ctx->msg->data_type != OID_msIndirectData &&
 529                    ctx->msg->data_type != OID_data) {
 530#else
 531                if (ctx->msg->data_type != OID_msIndirectData) {
 532#endif
 533                        pr_warn("S/MIME Caps only allowed with Authenticode\n");
 534                        return -EKEYREJECTED;
 535                }
 536                return 0;
 537
 538                /* Microsoft SpOpusInfo seems to be contain cont[0] 16-bit BE
 539                 * char URLs and cont[1] 8-bit char URLs.
 540                 *
 541                 * Microsoft StatementType seems to contain a list of OIDs that
 542                 * are also used as extendedKeyUsage types in X.509 certs.
 543                 */
 544        case OID_msSpOpusInfo:
 545                if (__test_and_set_bit(sinfo_has_ms_opus_info, &sinfo->aa_set))
 546                        goto repeated;
 547                goto authenticode_check;
 548        case OID_msStatementType:
 549                if (__test_and_set_bit(sinfo_has_ms_statement_type, &sinfo->aa_set))
 550                        goto repeated;
 551        authenticode_check:
 552                if (ctx->msg->data_type != OID_msIndirectData) {
 553                        pr_warn("Authenticode AuthAttrs only allowed with Authenticode\n");
 554                        return -EKEYREJECTED;
 555                }
 556                /* I'm not sure how to validate these */
 557                return 0;
 558        default:
 559                return 0;
 560        }
 561
 562repeated:
 563        /* We permit max one item per AuthenticatedAttribute and no repeats */
 564        pr_warn("Repeated/multivalue AuthAttrs not permitted\n");
 565        return -EKEYREJECTED;
 566}
 567
 568/*
 569 * Note the set of auth attributes for digestion purposes [RFC2315 sec 9.3]
 570 */
 571int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen,
 572                                    unsigned char tag,
 573                                    const void *value, size_t vlen)
 574{
 575        struct pkcs7_parse_context *ctx = context;
 576        struct pkcs7_signed_info *sinfo = ctx->sinfo;
 577
 578        if (!test_bit(sinfo_has_content_type, &sinfo->aa_set) ||
 579            !test_bit(sinfo_has_message_digest, &sinfo->aa_set)) {
 580                pr_warn("Missing required AuthAttr\n");
 581                return -EBADMSG;
 582        }
 583
 584        if (ctx->msg->data_type != OID_msIndirectData &&
 585            test_bit(sinfo_has_ms_opus_info, &sinfo->aa_set)) {
 586                pr_warn("Unexpected Authenticode AuthAttr\n");
 587                return -EBADMSG;
 588        }
 589
 590        /* We need to switch the 'CONT 0' to a 'SET OF' when we digest */
 591        sinfo->authattrs = value - (hdrlen - 1);
 592        sinfo->authattrs_len = vlen + (hdrlen - 1);
 593        return 0;
 594}
 595
 596/*
 597 * Note the issuing certificate serial number
 598 */
 599int pkcs7_sig_note_serial(void *context, size_t hdrlen,
 600                          unsigned char tag,
 601                          const void *value, size_t vlen)
 602{
 603        struct pkcs7_parse_context *ctx = context;
 604        ctx->raw_serial = value;
 605        ctx->raw_serial_size = vlen;
 606        return 0;
 607}
 608
 609/*
 610 * Note the issuer's name
 611 */
 612int pkcs7_sig_note_issuer(void *context, size_t hdrlen,
 613                          unsigned char tag,
 614                          const void *value, size_t vlen)
 615{
 616        struct pkcs7_parse_context *ctx = context;
 617        ctx->raw_issuer = value;
 618        ctx->raw_issuer_size = vlen;
 619        return 0;
 620}
 621
 622/*
 623 * Note the issuing cert's subjectKeyIdentifier
 624 */
 625int pkcs7_sig_note_skid(void *context, size_t hdrlen,
 626                        unsigned char tag,
 627                        const void *value, size_t vlen)
 628{
 629        struct pkcs7_parse_context *ctx = context;
 630
 631        pr_devel("SKID: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value);
 632
 633        ctx->raw_skid = value;
 634        ctx->raw_skid_size = vlen;
 635        return 0;
 636}
 637
 638/*
 639 * Note the signature data
 640 */
 641int pkcs7_sig_note_signature(void *context, size_t hdrlen,
 642                             unsigned char tag,
 643                             const void *value, size_t vlen)
 644{
 645        struct pkcs7_parse_context *ctx = context;
 646
 647        ctx->sinfo->sig->s = kmemdup(value, vlen, GFP_KERNEL);
 648        if (!ctx->sinfo->sig->s)
 649                return -ENOMEM;
 650
 651        ctx->sinfo->sig->s_size = vlen;
 652        return 0;
 653}
 654
 655/*
 656 * Note a signature information block
 657 */
 658int pkcs7_note_signed_info(void *context, size_t hdrlen,
 659                           unsigned char tag,
 660                           const void *value, size_t vlen)
 661{
 662        struct pkcs7_parse_context *ctx = context;
 663        struct pkcs7_signed_info *sinfo = ctx->sinfo;
 664        struct asymmetric_key_id *kid;
 665
 666        if (ctx->msg->data_type == OID_msIndirectData && !sinfo->authattrs) {
 667                pr_warn("Authenticode requires AuthAttrs\n");
 668                return -EBADMSG;
 669        }
 670
 671        /* Generate cert issuer + serial number key ID */
 672        if (!ctx->expect_skid) {
 673                kid = asymmetric_key_generate_id(ctx->raw_serial,
 674                                                 ctx->raw_serial_size,
 675                                                 ctx->raw_issuer,
 676                                                 ctx->raw_issuer_size);
 677        } else {
 678                kid = asymmetric_key_generate_id(ctx->raw_skid,
 679                                                 ctx->raw_skid_size,
 680                                                 "", 0);
 681        }
 682        if (IS_ERR(kid))
 683                return PTR_ERR(kid);
 684
 685        pr_devel("SINFO KID: %u [%*phN]\n", kid->len, kid->len, kid->data);
 686
 687        sinfo->sig->auth_ids[0] = kid;
 688        sinfo->index = ++ctx->sinfo_index;
 689        *ctx->ppsinfo = sinfo;
 690        ctx->ppsinfo = &sinfo->next;
 691        ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
 692        if (!ctx->sinfo)
 693                return -ENOMEM;
 694        ctx->sinfo->sig = kzalloc(sizeof(struct public_key_signature),
 695                                  GFP_KERNEL);
 696        if (!ctx->sinfo->sig)
 697                return -ENOMEM;
 698        return 0;
 699}
 700