Coverage Report

Created: 2026-11-12 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnutls/lib/x509/pkcs7-output.c
Line
Count
Source
1
/*
2
 * Copyright (C) 2015 Red Hat, Inc.
3
 *
4
 * Author: Nikos Mavrogiannopoulos
5
 *
6
 * This file is part of GnuTLS.
7
 *
8
 * The GnuTLS is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public License
10
 * as published by the Free Software Foundation; either version 2.1 of
11
 * the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful, but
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
20
 *
21
 */
22
23
#include "gnutls_int.h"
24
#include "common.h"
25
#include "x509.h"
26
#include "x509_int.h"
27
#include "num.h"
28
#include "errors.h"
29
#include "extras/randomart.h"
30
#include "pkcs7_int.h"
31
32
31.1k
#define addf _gnutls_buffer_append_printf
33
1.64M
#define adds _gnutls_buffer_append_str
34
35
static void print_dn(gnutls_buffer_st *str, const char *prefix,
36
         const gnutls_datum_t *raw)
37
7.73k
{
38
7.73k
  gnutls_x509_dn_t dn = NULL;
39
7.73k
  gnutls_datum_t output = { NULL, 0 };
40
7.73k
  int ret;
41
42
7.73k
  ret = gnutls_x509_dn_init(&dn);
43
7.73k
  if (ret < 0) {
44
0
    addf(str, "%s: [error]\n", prefix);
45
0
    return;
46
0
  }
47
48
7.73k
  ret = gnutls_x509_dn_import(dn, raw);
49
7.73k
  if (ret < 0) {
50
89
    addf(str, "%s: [error]\n", prefix);
51
89
    goto cleanup;
52
89
  }
53
54
7.64k
  ret = gnutls_x509_dn_get_str2(dn, &output, 0);
55
7.64k
  if (ret < 0) {
56
3.24k
    addf(str, "%s: [error]\n", prefix);
57
3.24k
    goto cleanup;
58
3.24k
  }
59
60
4.39k
  addf(str, "%s: %s\n", prefix, output.data);
61
62
7.73k
cleanup:
63
7.73k
  gnutls_x509_dn_deinit(dn);
64
7.73k
  gnutls_free(output.data);
65
7.73k
}
66
67
/* Do not encode ASN1 and type for now */
68
#define ENTRY(oid, name, type) \
69
  { oid, sizeof(oid) - 1, name, sizeof(name) - 1, NULL, type }
70
#define ENTRY2(oid, name)                                        \
71
  {                                                        \
72
    oid,  sizeof(oid) - 1,   name, sizeof(name) - 1, \
73
    NULL, ASN1_ETYPE_INVALID                         \
74
  }
75
76
static const struct oid_to_string pkcs7_attrs[] = {
77
  ENTRY("1.2.840.113549.1.9.3", "contentType", ASN1_ETYPE_OBJECT_ID),
78
  ENTRY("1.2.840.113549.1.9.4", "messageDigest", ASN1_ETYPE_OCTET_STRING),
79
  ENTRY("1.2.840.113549.1.9.5", "signingTime", ASN1_ETYPE_INVALID),
80
  ENTRY2("1.2.840.113549.1.9.6", "countersignature"),
81
  ENTRY2("1.2.840.113549.1.9.15", "smimeCapabilities"),
82
83
  ENTRY2("1.2.840.113549.1.9.16.2.1", "aa-receiptRequest"),
84
  ENTRY2("1.2.840.113549.1.9.16.2.2", "aa-securityLabel"),
85
  ENTRY2("1.2.840.113549.1.9.16.2.3", "aa-mlExpandHistory"),
86
  ENTRY2("1.2.840.113549.1.9.16.2.4", "aa-contentHint"),
87
  ENTRY2("1.2.840.113549.1.9.16.2.9", "aa-equivalentLabels"),
88
  ENTRY2("1.2.840.113549.1.9.16.2.10", "aa-contentReference"),
89
  ENTRY2("1.2.840.113549.1.9.16.2.11", "aa-encrypKeyPref"),
90
  ENTRY2("1.2.840.113549.1.9.16.2.12", "aa-signingCertificate"),
91
  ENTRY2("1.2.840.113549.1.9.16.2.19", "aa-ets-otherSigCert"),
92
  ENTRY2("1.2.840.113549.1.9.16.2.47", "aa-signingCertificateV2"),
93
94
  { NULL, 0, NULL, 0, NULL, 0 }
95
};
96
97
static void print_raw(gnutls_buffer_st *str, const char *prefix,
98
          const gnutls_datum_t *raw)
99
19.5k
{
100
19.5k
  gnutls_datum_t result;
101
19.5k
  int ret;
102
103
19.5k
  if (raw->data == NULL || raw->size == 0)
104
9.77k
    return;
105
106
9.77k
  ret = gnutls_hex_encode2(raw, &result);
107
9.77k
  if (ret < 0) {
108
0
    addf(str, "%s: [error]\n", prefix);
109
0
    return;
110
0
  }
111
112
9.77k
  addf(str, "%s: %s\n", prefix, result.data);
113
9.77k
  gnutls_free(result.data);
114
9.77k
}
115
116
static void print_pkcs7_info(gnutls_pkcs7_signature_info_st *info,
117
           gnutls_buffer_st *str,
118
           gnutls_certificate_print_formats_t format)
119
9.77k
{
120
9.77k
  unsigned i;
121
9.77k
  char *oid;
122
9.77k
  gnutls_datum_t data;
123
9.77k
  char prefix[128];
124
9.77k
  char s[42];
125
9.77k
  size_t max;
126
9.77k
  int ret;
127
9.77k
  const struct oid_to_string *entry;
128
129
9.77k
  if (info->issuer_dn.size > 0)
130
7.73k
    print_dn(str, "\tSigner's issuer DN", &info->issuer_dn);
131
9.77k
  print_raw(str, "\tSigner's serial", &info->signer_serial);
132
9.77k
  print_raw(str, "\tSigner's issuer key ID", &info->issuer_keyid);
133
9.77k
  if (info->signing_time != -1) {
134
0
    struct tm t;
135
0
    if (gmtime_r(&info->signing_time, &t) == NULL) {
136
0
      addf(str, "error: gmtime_r (%ld)\n",
137
0
           (unsigned long)info->signing_time);
138
0
    } else {
139
0
      max = sizeof(s);
140
0
      if (strftime(s, max, "%a %b %d %H:%M:%S UTC %Y", &t) ==
141
0
          0) {
142
0
        addf(str, "error: strftime (%ld)\n",
143
0
             (unsigned long)info->signing_time);
144
0
      } else {
145
0
        addf(str, "\tSigning time: %s\n", s);
146
0
      }
147
0
    }
148
0
  }
149
150
9.77k
  addf(str, "\tSignature Algorithm: %s\n",
151
9.77k
       gnutls_sign_get_name(info->algo));
152
153
9.77k
  if (format == GNUTLS_CRT_PRINT_FULL) {
154
9.77k
    if (info->signed_attrs) {
155
0
      for (i = 0;; i++) {
156
0
        ret = gnutls_pkcs7_get_attr(info->signed_attrs,
157
0
                  i, &oid, &data, 0);
158
0
        if (ret < 0)
159
0
          break;
160
0
        if (i == 0)
161
0
          addf(str, "\tSigned Attributes:\n");
162
163
0
        entry = _gnutls_oid_get_entry(pkcs7_attrs, oid);
164
0
        snprintf(prefix, sizeof(prefix), "\t\t%s",
165
0
           (entry && entry->name_desc) ?
166
0
             entry->name_desc :
167
0
             oid);
168
0
        print_raw(str, prefix, &data);
169
0
        gnutls_free(data.data);
170
0
      }
171
0
    }
172
9.77k
    if (info->unsigned_attrs) {
173
0
      for (i = 0;; i++) {
174
0
        ret = gnutls_pkcs7_get_attr(
175
0
          info->unsigned_attrs, i, &oid, &data,
176
0
          0);
177
0
        if (ret < 0)
178
0
          break;
179
0
        if (i == 0)
180
0
          addf(str, "\tUnsigned Attributes:\n");
181
182
0
        entry = _gnutls_oid_get_entry(pkcs7_attrs, oid);
183
0
        snprintf(prefix, sizeof(prefix), "\t\t%s",
184
0
           (entry && entry->name_desc) ?
185
0
             entry->name_desc :
186
0
             oid);
187
0
        print_raw(str, prefix, &data);
188
0
        gnutls_free(data.data);
189
0
      }
190
0
    }
191
9.77k
  }
192
9.77k
  adds(str, "\n");
193
9.77k
}
194
195
/**
196
 * gnutls_pkcs7_print_signature_info:
197
 * @info: The PKCS7 signature info struct to be printed
198
 * @format: Indicate the format to use
199
 * @out: Newly allocated datum with null terminated string.
200
 *
201
 * This function will pretty print a PKCS #7 signature info structure, suitable
202
 * for display to a human.
203
 *
204
 * Currently the supported formats are %GNUTLS_CRT_PRINT_FULL and
205
 * %GNUTLS_CRT_PRINT_COMPACT.
206
 *
207
 * The output @out needs to be deallocated using gnutls_free().
208
 *
209
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
210
 *   negative error value.
211
 *
212
 * Since: 3.6.14
213
 **/
214
int gnutls_pkcs7_print_signature_info(gnutls_pkcs7_signature_info_st *info,
215
              gnutls_certificate_print_formats_t format,
216
              gnutls_datum_t *out)
217
0
{
218
0
  gnutls_buffer_st str;
219
220
0
  _gnutls_buffer_init(&str);
221
0
  print_pkcs7_info(info, &str, format);
222
223
0
  return _gnutls_buffer_to_datum(&str, out, 1);
224
0
}
225
226
/**
227
 * gnutls_pkcs7_crt_print:
228
 * @pkcs7: The PKCS7 struct to be printed
229
 * @format: Indicate the format to use
230
 * @out: Newly allocated datum with null terminated string.
231
 *
232
 * This function will pretty print a signed PKCS #7 structure, suitable for
233
 * display to a human.
234
 *
235
 * Currently the supported formats are %GNUTLS_CRT_PRINT_FULL and
236
 * %GNUTLS_CRT_PRINT_COMPACT.
237
 *
238
 * The output @out needs to be deallocated using gnutls_free().
239
 *
240
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
241
 *   negative error value.
242
 **/
243
int gnutls_pkcs7_print(gnutls_pkcs7_t pkcs7,
244
           gnutls_certificate_print_formats_t format,
245
           gnutls_datum_t *out)
246
1.72k
{
247
1.72k
  int count, ret, i;
248
1.72k
  gnutls_pkcs7_signature_info_st info;
249
1.72k
  gnutls_buffer_st str;
250
1.72k
  const char *oid;
251
252
1.72k
  _gnutls_buffer_init(&str);
253
254
  /* For backwards compatibility with structures using the default OID,
255
   * we don't print the eContent Type explicitly */
256
1.72k
  oid = gnutls_pkcs7_get_embedded_data_oid(pkcs7);
257
1.72k
  if (oid) {
258
1.72k
    if (!streq(oid, DATA_OID) && !streq(oid, DIGESTED_DATA_OID)) {
259
1.71k
      addf(&str, "eContent Type: %s\n", oid);
260
1.71k
    }
261
1.72k
  }
262
263
11.5k
  for (i = 0;; i++) {
264
11.5k
    if (i == 0)
265
1.72k
      addf(&str, "Signers:\n");
266
267
11.5k
    ret = gnutls_pkcs7_get_signature_info(pkcs7, i, &info);
268
11.5k
    if (ret < 0)
269
1.72k
      break;
270
271
9.77k
    print_pkcs7_info(&info, &str, format);
272
9.77k
    gnutls_pkcs7_signature_info_deinit(&info);
273
9.77k
  }
274
275
1.72k
  if (format == GNUTLS_CRT_PRINT_FULL) {
276
1.72k
    gnutls_datum_t data, b64;
277
278
1.72k
    count = gnutls_pkcs7_get_crt_count(pkcs7);
279
280
1.72k
    if (count > 0) {
281
253
      addf(&str, "Number of certificates: %u\n\n", count);
282
283
730k
      for (i = 0; i < count; i++) {
284
730k
        ret = gnutls_pkcs7_get_crt_raw2(pkcs7, i,
285
730k
                &data);
286
730k
        if (ret < 0) {
287
0
          addf(&str,
288
0
               "Error: cannot print certificate %d\n",
289
0
               i);
290
0
          continue;
291
0
        }
292
293
730k
        ret = gnutls_pem_base64_encode_alloc(
294
730k
          "CERTIFICATE", &data, &b64);
295
730k
        if (ret < 0) {
296
0
          gnutls_free(data.data);
297
0
          continue;
298
0
        }
299
300
730k
        adds(&str, (char *)b64.data);
301
730k
        adds(&str, "\n");
302
730k
        gnutls_free(b64.data);
303
730k
        gnutls_free(data.data);
304
730k
      }
305
253
    }
306
307
1.72k
    count = gnutls_pkcs7_get_crl_count(pkcs7);
308
1.72k
    if (count > 0) {
309
145
      addf(&str, "Number of CRLs: %u\n\n", count);
310
311
86.9k
      for (i = 0; i < count; i++) {
312
86.8k
        ret = gnutls_pkcs7_get_crl_raw2(pkcs7, i,
313
86.8k
                &data);
314
86.8k
        if (ret < 0) {
315
0
          addf(&str,
316
0
               "Error: cannot print certificate %d\n",
317
0
               i);
318
0
          continue;
319
0
        }
320
321
86.8k
        ret = gnutls_pem_base64_encode_alloc(
322
86.8k
          "X509 CRL", &data, &b64);
323
86.8k
        if (ret < 0) {
324
0
          gnutls_free(data.data);
325
0
          continue;
326
0
        }
327
328
86.8k
        adds(&str, (char *)b64.data);
329
86.8k
        adds(&str, "\n");
330
86.8k
        gnutls_free(b64.data);
331
86.8k
        gnutls_free(data.data);
332
86.8k
      }
333
145
    }
334
1.72k
  }
335
336
1.72k
  return _gnutls_buffer_to_datum(&str, out, 1);
337
1.72k
}