blob: 5ef8898aa08ac23066e77e60514602aba2199a01 [file] [log] [blame]
Adam Tkac68481c12011-02-09 14:15:09 +00001/* Copyright (C) 2011 TightVNC Team. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18
19#ifdef HAVE_CONFIG_H
20#include <config.h>
21#endif
22
23#include <os/tls.h>
24
25#include <iomanip>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <sstream>
30#include <sys/types.h>
31#include <time.h>
32
33using namespace std;
34
35#ifdef HAVE_GNUTLS
36#include <gnutls/gnutls.h>
37#include <gnutls/x509.h>
38
39#ifndef HAVE_GNUTLS_X509_CRT_PRINT
40
41#define UNKNOWN_SUBJECT(err) \
42 do { \
43 ss << "unknown subject (" << gnutls_strerror(err) << "), "; \
44 } while (0)
45
46#define UNKNOWN_ISSUER(err) \
47 do { \
48 ss << "unknown issuer (" << gnutls_strerror(err) << "), "; \
49 } while (0)
50
51
52static void
53hexprint(ostringstream &ss, const char *data, size_t len)
54{
55 size_t j;
56 char tmp[3];
57
58 if (len == 0)
59 ss << "00";
60 else {
61 for (j = 0; j < len; j++) {
62 snprintf(tmp, sizeof(tmp), "%.2x", (unsigned char) data[j]);
63 ss << tmp;
64 }
65 }
66}
67
68/* Implementation based on gnutls_x509_crt_print from GNUTLS */
69int
70gnutls_x509_crt_print(gnutls_x509_crt_t cert,
71 gnutls_certificate_print_formats_t format,
72 gnutls_datum_t * out)
73{
74 ostringstream ss;
75
76 int err;
77
78 char *dn;
79 size_t dn_size = 0;
80
81 /* Subject */
82 err = gnutls_x509_crt_get_dn(cert, NULL, &dn_size);
83 if (err != GNUTLS_E_SHORT_MEMORY_BUFFER)
84 UNKNOWN_SUBJECT(err);
85 else {
86 dn = (char *)malloc(dn_size);
87 if (dn == NULL) {
88 UNKNOWN_SUBJECT(GNUTLS_E_MEMORY_ERROR);
89 } else {
90 err = gnutls_x509_crt_get_dn(cert, dn, &dn_size);
91 if (err < 0) {
92 UNKNOWN_SUBJECT(err);
93 } else
94 ss << "subject `" << dn << "', ";
95 free(dn);
96 }
97 }
98
99 /* Issuer */
100 dn = NULL;
101 dn_size = 0;
102 err = gnutls_x509_crt_get_issuer_dn(cert, NULL, &dn_size);
103 if (err != GNUTLS_E_SHORT_MEMORY_BUFFER)
104 UNKNOWN_ISSUER(err);
105 else {
106 dn = (char *)malloc(dn_size);
107 if (dn == NULL) {
108 UNKNOWN_ISSUER(GNUTLS_E_MEMORY_ERROR);
109 } else {
110 err = gnutls_x509_crt_get_issuer_dn(cert, dn, &dn_size);
111 if (err < 0)
112 UNKNOWN_ISSUER(err);
113 else
114 ss << "issuer `" << dn << "', ";
115 free(dn);
116 }
117 }
118
119 /* Key algorithm and size */
120 unsigned int bits;
121 const char *name;
122 name = gnutls_pk_algorithm_get_name( (gnutls_pk_algorithm_t)
123 gnutls_x509_crt_get_pk_algorithm(cert, &bits));
124 if (name == NULL)
125 name = "Unknown";
126 ss << name << " key " << bits << " bits, ";
127
128 /* Signature algorithm */
129 err = gnutls_x509_crt_get_signature_algorithm(cert);
130 if (err < 0) {
131 ss << "unknown signature algorithm (" << gnutls_strerror(err)
132 << "), ";
133 } else {
134 const char *name;
135 name = gnutls_sign_algorithm_get_name((gnutls_sign_algorithm_t)err);
136 if (name == NULL)
137 name = "Unknown";
138
139 ss << "signed using " << name;
140 if (err == GNUTLS_SIGN_RSA_MD5 || err == GNUTLS_SIGN_RSA_MD2)
141 ss << " (broken!)";
142 ss << ", ";
143 }
144
145 /* Validity */
146 time_t tim;
147 char s[42];
148 size_t max = sizeof(s);
149 struct tm t;
150
151 tim = gnutls_x509_crt_get_activation_time(cert);
152 if (gmtime_r(&tim, &t) == NULL)
153 ss << "unknown activation (" << (unsigned long) tim << ")";
154 else if (strftime(s, max, "%Y-%m-%d %H:%M:%S UTC", &t) == 0)
155 ss << "failed activation (" << (unsigned long) tim << ")";
156 else
157 ss << "activated `" << s << "'";
158 ss << ", ";
159
160 tim = gnutls_x509_crt_get_expiration_time(cert);
161 if (gmtime_r(&tim, &t) == NULL)
162 ss << "unknown expiry (" << (unsigned long) tim << ")";
163 else if (strftime(s, max, "%Y-%m-%d %H:%M:%S UTC", &t) == 0)
164 ss << "failed expiry (" << (unsigned long) tim << ")";
165 else
166 ss << "expires `" << s << "'";
167 ss << ", ";
168
169 /* Fingerprint */
170 char buffer[20];
171 size_t size = sizeof(buffer);
172
173 err = gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, buffer, &size);
174 if (err < 0)
175 ss << "unknown fingerprint (" << gnutls_strerror(err) << ")";
176 else {
177 ss << "SHA-1 fingerprint `";
178 hexprint(ss, buffer, size);
179 ss << "'";
180 }
181
182 out->data = (unsigned char *) strdup(ss.str().c_str());
183 if (out->data == NULL)
184 return GNUTLS_E_MEMORY_ERROR;
185 out->size = strlen((char *)out->data);
186
187 return 0;
188}
189
190#endif /* HAVE_GNUTLS_X509_CRT_PRINT */
191
192#endif /* HAVE_GNUTLS */
193