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