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 #define addf _gnutls_buffer_append_printf
33 #define adds _gnutls_buffer_append_str
34
print_dn(gnutls_buffer_st * str,const char * prefix,const gnutls_datum_t * raw)35 static void print_dn(gnutls_buffer_st * str, const char *prefix,
36 const gnutls_datum_t * raw)
37 {
38 gnutls_x509_dn_t dn = NULL;
39 gnutls_datum_t output = { NULL, 0 };
40 int ret;
41
42 ret = gnutls_x509_dn_init(&dn);
43 if (ret < 0) {
44 addf(str, "%s: [error]\n", prefix);
45 return;
46 }
47
48 ret = gnutls_x509_dn_import(dn, raw);
49 if (ret < 0) {
50 addf(str, "%s: [error]\n", prefix);
51 goto cleanup;
52 }
53
54 ret = gnutls_x509_dn_get_str2(dn, &output, 0);
55 if (ret < 0) {
56 addf(str, "%s: [error]\n", prefix);
57 goto cleanup;
58 }
59
60 addf(str, "%s: %s\n", prefix, output.data);
61
62 cleanup:
63 gnutls_x509_dn_deinit(dn);
64 gnutls_free(output.data);
65 }
66
67 /* Do not encode ASN1 and type for now */
68 #define ENTRY(oid, name, type) {oid, sizeof(oid)-1, name, sizeof(name)-1, NULL, type}
69 #define ENTRY2(oid, name) {oid, sizeof(oid)-1, name, sizeof(name)-1, NULL, ASN1_ETYPE_INVALID}
70
71 static const struct oid_to_string pkcs7_attrs[] = {
72 ENTRY ("1.2.840.113549.1.9.3", "contentType", ASN1_ETYPE_OBJECT_ID),
73 ENTRY ("1.2.840.113549.1.9.4", "messageDigest", ASN1_ETYPE_OCTET_STRING),
74 ENTRY ("1.2.840.113549.1.9.5", "signingTime", ASN1_ETYPE_INVALID),
75 ENTRY2("1.2.840.113549.1.9.6", "countersignature"),
76 ENTRY2("1.2.840.113549.1.9.15", "smimeCapabilities"),
77
78 ENTRY2("1.2.840.113549.1.9.16.2.1", "aa-receiptRequest"),
79 ENTRY2("1.2.840.113549.1.9.16.2.2", "aa-securityLabel"),
80 ENTRY2("1.2.840.113549.1.9.16.2.3", "aa-mlExpandHistory"),
81 ENTRY2("1.2.840.113549.1.9.16.2.4", "aa-contentHint"),
82 ENTRY2("1.2.840.113549.1.9.16.2.9", "aa-equivalentLabels"),
83 ENTRY2("1.2.840.113549.1.9.16.2.10", "aa-contentReference"),
84 ENTRY2("1.2.840.113549.1.9.16.2.11", "aa-encrypKeyPref"),
85 ENTRY2("1.2.840.113549.1.9.16.2.12", "aa-signingCertificate"),
86 ENTRY2("1.2.840.113549.1.9.16.2.19", "aa-ets-otherSigCert"),
87 ENTRY2("1.2.840.113549.1.9.16.2.47", "aa-signingCertificateV2"),
88
89 {NULL, 0, NULL, 0, NULL, 0}
90 };
91
print_raw(gnutls_buffer_st * str,const char * prefix,const gnutls_datum_t * raw)92 static void print_raw(gnutls_buffer_st * str, const char *prefix,
93 const gnutls_datum_t * raw)
94 {
95 gnutls_datum_t result;
96 int ret;
97
98 if (raw->data == NULL || raw->size == 0)
99 return;
100
101 ret = gnutls_hex_encode2(raw, &result);
102 if (ret < 0) {
103 addf(str, "%s: [error]\n", prefix);
104 return;
105 }
106
107 addf(str, "%s: %s\n", prefix, result.data);
108 gnutls_free(result.data);
109 }
110
print_pkcs7_info(gnutls_pkcs7_signature_info_st * info,gnutls_buffer_st * str,gnutls_certificate_print_formats_t format)111 static void print_pkcs7_info(gnutls_pkcs7_signature_info_st * info,
112 gnutls_buffer_st * str,
113 gnutls_certificate_print_formats_t format)
114 {
115 unsigned i;
116 char *oid;
117 gnutls_datum_t data;
118 char prefix[128];
119 char s[42];
120 size_t max;
121 int ret;
122 const struct oid_to_string * entry;
123
124 if (info->issuer_dn.size > 0)
125 print_dn(str, "\tSigner's issuer DN", &info->issuer_dn);
126 print_raw(str, "\tSigner's serial", &info->signer_serial);
127 print_raw(str, "\tSigner's issuer key ID", &info->issuer_keyid);
128 if (info->signing_time != -1) {
129 struct tm t;
130 if (gmtime_r(&info->signing_time, &t) == NULL) {
131 addf(str, "error: gmtime_r (%ld)\n",
132 (unsigned long)info->signing_time);
133 } else {
134 max = sizeof(s);
135 if (strftime(s, max, "%a %b %d %H:%M:%S UTC %Y", &t) ==
136 0) {
137 addf(str, "error: strftime (%ld)\n",
138 (unsigned long)info->signing_time);
139 } else {
140 addf(str, "\tSigning time: %s\n", s);
141 }
142 }
143 }
144
145 addf(str, "\tSignature Algorithm: %s\n",
146 gnutls_sign_get_name(info->algo));
147
148 if (format == GNUTLS_CRT_PRINT_FULL) {
149 if (info->signed_attrs) {
150 for (i = 0;; i++) {
151 ret =
152 gnutls_pkcs7_get_attr(info->signed_attrs, i,
153 &oid, &data, 0);
154 if (ret < 0)
155 break;
156 if (i == 0)
157 addf(str, "\tSigned Attributes:\n");
158
159 entry = _gnutls_oid_get_entry(pkcs7_attrs, oid);
160 snprintf(prefix, sizeof(prefix), "\t\t%s",
161 (entry && entry->name_desc) ? entry->name_desc : oid);
162 print_raw(str, prefix, &data);
163 gnutls_free(data.data);
164 }
165 }
166 if (info->unsigned_attrs) {
167 for (i = 0;; i++) {
168 ret =
169 gnutls_pkcs7_get_attr(info->unsigned_attrs,
170 i, &oid, &data, 0);
171 if (ret < 0)
172 break;
173 if (i == 0)
174 addf(str, "\tUnsigned Attributes:\n");
175
176 entry = _gnutls_oid_get_entry(pkcs7_attrs, oid);
177 snprintf(prefix, sizeof(prefix), "\t\t%s",
178 (entry && entry->name_desc) ? entry->name_desc : oid);
179 print_raw(str, prefix, &data);
180 gnutls_free(data.data);
181 }
182 }
183 }
184 adds(str, "\n");
185 }
186
187 /**
188 * gnutls_pkcs7_print_signature_info:
189 * @info: The PKCS7 signature info struct to be printed
190 * @format: Indicate the format to use
191 * @out: Newly allocated datum with null terminated string.
192 *
193 * This function will pretty print a PKCS #7 signature info structure, suitable
194 * for display to a human.
195 *
196 * Currently the supported formats are %GNUTLS_CRT_PRINT_FULL and
197 * %GNUTLS_CRT_PRINT_COMPACT.
198 *
199 * The output @out needs to be deallocated using gnutls_free().
200 *
201 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
202 * negative error value.
203 *
204 * Since: 3.6.14
205 **/
gnutls_pkcs7_print_signature_info(gnutls_pkcs7_signature_info_st * info,gnutls_certificate_print_formats_t format,gnutls_datum_t * out)206 int gnutls_pkcs7_print_signature_info(gnutls_pkcs7_signature_info_st * info,
207 gnutls_certificate_print_formats_t format,
208 gnutls_datum_t * out)
209 {
210 gnutls_buffer_st str;
211
212 _gnutls_buffer_init(&str);
213 print_pkcs7_info(info, &str, format);
214
215 return _gnutls_buffer_to_datum(&str, out, 1);
216 }
217
218 /**
219 * gnutls_pkcs7_crt_print:
220 * @pkcs7: The PKCS7 struct to be printed
221 * @format: Indicate the format to use
222 * @out: Newly allocated datum with null terminated string.
223 *
224 * This function will pretty print a signed PKCS #7 structure, suitable for
225 * display to a human.
226 *
227 * Currently the supported formats are %GNUTLS_CRT_PRINT_FULL and
228 * %GNUTLS_CRT_PRINT_COMPACT.
229 *
230 * The output @out needs to be deallocated using gnutls_free().
231 *
232 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
233 * negative error value.
234 **/
gnutls_pkcs7_print(gnutls_pkcs7_t pkcs7,gnutls_certificate_print_formats_t format,gnutls_datum_t * out)235 int gnutls_pkcs7_print(gnutls_pkcs7_t pkcs7,
236 gnutls_certificate_print_formats_t format,
237 gnutls_datum_t * out)
238 {
239 int count, ret, i;
240 gnutls_pkcs7_signature_info_st info;
241 gnutls_buffer_st str;
242 const char *oid;
243
244 _gnutls_buffer_init(&str);
245
246 /* For backwards compatibility with structures using the default OID,
247 * we don't print the eContent Type explicitly */
248 oid = gnutls_pkcs7_get_embedded_data_oid(pkcs7);
249 if (oid) {
250 if (strcmp(oid, DATA_OID) != 0
251 && strcmp(oid, DIGESTED_DATA_OID) != 0) {
252 addf(&str, "eContent Type: %s\n", oid);
253 }
254 }
255
256 for (i = 0;; i++) {
257 if (i == 0)
258 addf(&str, "Signers:\n");
259
260 ret = gnutls_pkcs7_get_signature_info(pkcs7, i, &info);
261 if (ret < 0)
262 break;
263
264 print_pkcs7_info(&info, &str, format);
265 gnutls_pkcs7_signature_info_deinit(&info);
266 }
267
268 if (format == GNUTLS_CRT_PRINT_FULL) {
269 gnutls_datum_t data, b64;
270
271 count = gnutls_pkcs7_get_crt_count(pkcs7);
272
273 if (count > 0) {
274 addf(&str, "Number of certificates: %u\n\n",
275 count);
276
277 for (i = 0; i < count; i++) {
278 ret =
279 gnutls_pkcs7_get_crt_raw2(pkcs7, i, &data);
280 if (ret < 0) {
281 addf(&str,
282 "Error: cannot print certificate %d\n",
283 i);
284 continue;
285 }
286
287 ret =
288 gnutls_pem_base64_encode_alloc
289 ("CERTIFICATE", &data, &b64);
290 if (ret < 0) {
291 gnutls_free(data.data);
292 continue;
293 }
294
295 adds(&str, (char*)b64.data);
296 adds(&str, "\n");
297 gnutls_free(b64.data);
298 gnutls_free(data.data);
299 }
300 }
301
302 count = gnutls_pkcs7_get_crl_count(pkcs7);
303 if (count > 0) {
304 addf(&str, "Number of CRLs: %u\n\n", count);
305
306 for (i = 0; i < count; i++) {
307 ret =
308 gnutls_pkcs7_get_crl_raw2(pkcs7, i, &data);
309 if (ret < 0) {
310 addf(&str,
311 "Error: cannot print certificate %d\n",
312 i);
313 continue;
314 }
315
316 ret =
317 gnutls_pem_base64_encode_alloc("X509 CRL",
318 &data, &b64);
319 if (ret < 0) {
320 gnutls_free(data.data);
321 continue;
322 }
323
324 adds(&str, (char*)b64.data);
325 adds(&str, "\n");
326 gnutls_free(b64.data);
327 gnutls_free(data.data);
328 }
329 }
330 }
331
332 return _gnutls_buffer_to_datum(&str, out, 1);
333 }
334