blob: c09299682d315af47e3f515cf20a6fba3a7997ee [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
Adam Tkacd007ece2011-02-09 16:06:16 +000035#if defined(HAVE_GNUTLS) && !defined(WIN32)
Adam Tkac68481c12011-02-09 14:15:09 +000036#include <gnutls/gnutls.h>
37#include <gnutls/x509.h>
38
39#ifndef HAVE_GNUTLS_X509_CRT_PRINT
40
Adam Tkacb4864232011-02-09 15:38:37 +000041/* Ancient GNUTLS... */
42#if !defined(GNUTLS_VERSION_NUMBER) && !defined(LIBGNUTLS_VERSION_NUMBER)
43#define GNUTLS_DIG_SHA1 GNUTLS_DIG_SHA
44#endif
45
Adam Tkac68481c12011-02-09 14:15:09 +000046#define UNKNOWN_SUBJECT(err) \
47 do { \
48 ss << "unknown subject (" << gnutls_strerror(err) << "), "; \
49 } while (0)
50
51#define UNKNOWN_ISSUER(err) \
52 do { \
53 ss << "unknown issuer (" << gnutls_strerror(err) << "), "; \
54 } while (0)
55
56
57static void
58hexprint(ostringstream &ss, const char *data, size_t len)
59{
60 size_t j;
61 char tmp[3];
62
63 if (len == 0)
64 ss << "00";
65 else {
66 for (j = 0; j < len; j++) {
67 snprintf(tmp, sizeof(tmp), "%.2x", (unsigned char) data[j]);
68 ss << tmp;
69 }
70 }
71}
72
73/* Implementation based on gnutls_x509_crt_print from GNUTLS */
74int
75gnutls_x509_crt_print(gnutls_x509_crt_t cert,
76 gnutls_certificate_print_formats_t format,
77 gnutls_datum_t * out)
78{
79 ostringstream ss;
80
81 int err;
82
83 char *dn;
84 size_t dn_size = 0;
85
86 /* Subject */
87 err = gnutls_x509_crt_get_dn(cert, NULL, &dn_size);
88 if (err != GNUTLS_E_SHORT_MEMORY_BUFFER)
89 UNKNOWN_SUBJECT(err);
90 else {
91 dn = (char *)malloc(dn_size);
92 if (dn == NULL) {
93 UNKNOWN_SUBJECT(GNUTLS_E_MEMORY_ERROR);
94 } else {
95 err = gnutls_x509_crt_get_dn(cert, dn, &dn_size);
96 if (err < 0) {
97 UNKNOWN_SUBJECT(err);
98 } else
99 ss << "subject `" << dn << "', ";
100 free(dn);
101 }
102 }
103
104 /* Issuer */
105 dn = NULL;
106 dn_size = 0;
107 err = gnutls_x509_crt_get_issuer_dn(cert, NULL, &dn_size);
108 if (err != GNUTLS_E_SHORT_MEMORY_BUFFER)
109 UNKNOWN_ISSUER(err);
110 else {
111 dn = (char *)malloc(dn_size);
112 if (dn == NULL) {
113 UNKNOWN_ISSUER(GNUTLS_E_MEMORY_ERROR);
114 } else {
115 err = gnutls_x509_crt_get_issuer_dn(cert, dn, &dn_size);
116 if (err < 0)
117 UNKNOWN_ISSUER(err);
118 else
119 ss << "issuer `" << dn << "', ";
120 free(dn);
121 }
122 }
123
124 /* Key algorithm and size */
125 unsigned int bits;
126 const char *name;
127 name = gnutls_pk_algorithm_get_name( (gnutls_pk_algorithm_t)
128 gnutls_x509_crt_get_pk_algorithm(cert, &bits));
129 if (name == NULL)
130 name = "Unknown";
131 ss << name << " key " << bits << " bits, ";
132
133 /* Signature algorithm */
134 err = gnutls_x509_crt_get_signature_algorithm(cert);
135 if (err < 0) {
136 ss << "unknown signature algorithm (" << gnutls_strerror(err)
137 << "), ";
138 } else {
139 const char *name;
140 name = gnutls_sign_algorithm_get_name((gnutls_sign_algorithm_t)err);
141 if (name == NULL)
142 name = "Unknown";
143
144 ss << "signed using " << name;
145 if (err == GNUTLS_SIGN_RSA_MD5 || err == GNUTLS_SIGN_RSA_MD2)
146 ss << " (broken!)";
147 ss << ", ";
148 }
149
150 /* Validity */
151 time_t tim;
152 char s[42];
153 size_t max = sizeof(s);
154 struct tm t;
155
156 tim = gnutls_x509_crt_get_activation_time(cert);
157 if (gmtime_r(&tim, &t) == NULL)
158 ss << "unknown activation (" << (unsigned long) tim << ")";
159 else if (strftime(s, max, "%Y-%m-%d %H:%M:%S UTC", &t) == 0)
160 ss << "failed activation (" << (unsigned long) tim << ")";
161 else
162 ss << "activated `" << s << "'";
163 ss << ", ";
164
165 tim = gnutls_x509_crt_get_expiration_time(cert);
166 if (gmtime_r(&tim, &t) == NULL)
167 ss << "unknown expiry (" << (unsigned long) tim << ")";
168 else if (strftime(s, max, "%Y-%m-%d %H:%M:%S UTC", &t) == 0)
169 ss << "failed expiry (" << (unsigned long) tim << ")";
170 else
171 ss << "expires `" << s << "'";
172 ss << ", ";
173
174 /* Fingerprint */
175 char buffer[20];
176 size_t size = sizeof(buffer);
177
178 err = gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, buffer, &size);
179 if (err < 0)
180 ss << "unknown fingerprint (" << gnutls_strerror(err) << ")";
181 else {
182 ss << "SHA-1 fingerprint `";
183 hexprint(ss, buffer, size);
184 ss << "'";
185 }
186
187 out->data = (unsigned char *) strdup(ss.str().c_str());
188 if (out->data == NULL)
189 return GNUTLS_E_MEMORY_ERROR;
190 out->size = strlen((char *)out->data);
191
192 return 0;
193}
194
195#endif /* HAVE_GNUTLS_X509_CRT_PRINT */
196
197#endif /* HAVE_GNUTLS */
198