1 |
|
|
/* $OpenBSD: tls_conninfo.c,v 1.16 2017/08/27 01:39:26 beck Exp $ */ |
2 |
|
|
/* |
3 |
|
|
* Copyright (c) 2015 Joel Sing <jsing@openbsd.org> |
4 |
|
|
* Copyright (c) 2015 Bob Beck <beck@openbsd.org> |
5 |
|
|
* |
6 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
7 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
8 |
|
|
* copyright notice and this permission notice appear in all copies. |
9 |
|
|
* |
10 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 |
|
|
*/ |
18 |
|
|
|
19 |
|
|
#include <stdio.h> |
20 |
|
|
|
21 |
|
|
#include <openssl/x509.h> |
22 |
|
|
|
23 |
|
|
#include <tls.h> |
24 |
|
|
#include "tls_internal.h" |
25 |
|
|
|
26 |
|
|
int ASN1_time_tm_clamp_notafter(struct tm *tm); |
27 |
|
|
|
28 |
|
|
int |
29 |
|
|
tls_hex_string(const unsigned char *in, size_t inlen, char **out, |
30 |
|
|
size_t *outlen) |
31 |
|
|
{ |
32 |
|
|
static const char hex[] = "0123456789abcdef"; |
33 |
|
|
size_t i, len; |
34 |
|
|
char *p; |
35 |
|
|
|
36 |
✗✓ |
48 |
if (outlen != NULL) |
37 |
|
|
*outlen = 0; |
38 |
|
|
|
39 |
✗✓ |
24 |
if (inlen >= SIZE_MAX) |
40 |
|
|
return (-1); |
41 |
✗✓ |
24 |
if ((*out = reallocarray(NULL, inlen + 1, 2)) == NULL) |
42 |
|
|
return (-1); |
43 |
|
|
|
44 |
|
|
p = *out; |
45 |
|
|
len = 0; |
46 |
✓✓ |
1584 |
for (i = 0; i < inlen; i++) { |
47 |
|
768 |
p[len++] = hex[(in[i] >> 4) & 0x0f]; |
48 |
|
768 |
p[len++] = hex[in[i] & 0x0f]; |
49 |
|
|
} |
50 |
|
24 |
p[len++] = 0; |
51 |
|
|
|
52 |
✗✓ |
24 |
if (outlen != NULL) |
53 |
|
|
*outlen = len; |
54 |
|
|
|
55 |
|
24 |
return (0); |
56 |
|
24 |
} |
57 |
|
|
|
58 |
|
|
static int |
59 |
|
|
tls_get_peer_cert_hash(struct tls *ctx, char **hash) |
60 |
|
|
{ |
61 |
|
24 |
*hash = NULL; |
62 |
✗✓ |
12 |
if (ctx->ssl_peer_cert == NULL) |
63 |
|
|
return (0); |
64 |
|
|
|
65 |
✗✓ |
12 |
if (tls_cert_hash(ctx->ssl_peer_cert, hash) == -1) { |
66 |
|
|
tls_set_errorx(ctx, "unable to compute peer certificate hash - out of memory"); |
67 |
|
|
*hash = NULL; |
68 |
|
|
return -1; |
69 |
|
|
} |
70 |
|
12 |
return 0; |
71 |
|
12 |
} |
72 |
|
|
|
73 |
|
|
static int |
74 |
|
|
tls_get_peer_cert_issuer(struct tls *ctx, char **issuer) |
75 |
|
|
{ |
76 |
|
|
X509_NAME *name = NULL; |
77 |
|
|
|
78 |
|
24 |
*issuer = NULL; |
79 |
✗✓ |
12 |
if (ctx->ssl_peer_cert == NULL) |
80 |
|
|
return (-1); |
81 |
✗✓ |
12 |
if ((name = X509_get_issuer_name(ctx->ssl_peer_cert)) == NULL) |
82 |
|
|
return (-1); |
83 |
|
12 |
*issuer = X509_NAME_oneline(name, 0, 0); |
84 |
✗✓ |
12 |
if (*issuer == NULL) |
85 |
|
|
return (-1); |
86 |
|
12 |
return (0); |
87 |
|
12 |
} |
88 |
|
|
|
89 |
|
|
static int |
90 |
|
|
tls_get_peer_cert_subject(struct tls *ctx, char **subject) |
91 |
|
|
{ |
92 |
|
|
X509_NAME *name = NULL; |
93 |
|
|
|
94 |
|
24 |
*subject = NULL; |
95 |
✗✓ |
12 |
if (ctx->ssl_peer_cert == NULL) |
96 |
|
|
return (-1); |
97 |
✗✓ |
12 |
if ((name = X509_get_subject_name(ctx->ssl_peer_cert)) == NULL) |
98 |
|
|
return (-1); |
99 |
|
12 |
*subject = X509_NAME_oneline(name, 0, 0); |
100 |
✗✓ |
12 |
if (*subject == NULL) |
101 |
|
|
return (-1); |
102 |
|
12 |
return (0); |
103 |
|
12 |
} |
104 |
|
|
|
105 |
|
|
static int |
106 |
|
|
tls_get_peer_cert_times(struct tls *ctx, time_t *notbefore, |
107 |
|
|
time_t *notafter) |
108 |
|
|
{ |
109 |
|
24 |
struct tm before_tm, after_tm; |
110 |
|
|
ASN1_TIME *before, *after; |
111 |
|
|
|
112 |
✗✓ |
12 |
if (ctx->ssl_peer_cert == NULL) |
113 |
|
|
return (-1); |
114 |
|
|
|
115 |
|
12 |
memset(&before_tm, 0, sizeof(before_tm)); |
116 |
|
12 |
memset(&after_tm, 0, sizeof(after_tm)); |
117 |
|
|
|
118 |
✓✗ |
12 |
if ((before = X509_get_notBefore(ctx->ssl_peer_cert)) == NULL) |
119 |
|
|
goto err; |
120 |
✓✗ |
12 |
if ((after = X509_get_notAfter(ctx->ssl_peer_cert)) == NULL) |
121 |
|
|
goto err; |
122 |
✓✗ |
12 |
if (ASN1_time_parse(before->data, before->length, &before_tm, 0) == -1) |
123 |
|
|
goto err; |
124 |
✓✗ |
12 |
if (ASN1_time_parse(after->data, after->length, &after_tm, 0) == -1) |
125 |
|
|
goto err; |
126 |
✓✗ |
12 |
if (!ASN1_time_tm_clamp_notafter(&after_tm)) |
127 |
|
|
goto err; |
128 |
✓✗ |
12 |
if ((*notbefore = timegm(&before_tm)) == -1) |
129 |
|
|
goto err; |
130 |
✓✗ |
12 |
if ((*notafter = timegm(&after_tm)) == -1) |
131 |
|
|
goto err; |
132 |
|
|
|
133 |
|
12 |
return (0); |
134 |
|
|
|
135 |
|
|
err: |
136 |
|
|
return (-1); |
137 |
|
12 |
} |
138 |
|
|
|
139 |
|
|
static int |
140 |
|
|
tls_get_peer_cert_info(struct tls *ctx) |
141 |
|
|
{ |
142 |
✓✓ |
48 |
if (ctx->ssl_peer_cert == NULL) |
143 |
|
12 |
return (0); |
144 |
|
|
|
145 |
✓✗ |
12 |
if (tls_get_peer_cert_hash(ctx, &ctx->conninfo->hash) == -1) |
146 |
|
|
goto err; |
147 |
✓✗ |
12 |
if (tls_get_peer_cert_subject(ctx, &ctx->conninfo->subject) == -1) |
148 |
|
|
goto err; |
149 |
✓✗ |
12 |
if (tls_get_peer_cert_issuer(ctx, &ctx->conninfo->issuer) == -1) |
150 |
|
|
goto err; |
151 |
✓✗ |
36 |
if (tls_get_peer_cert_times(ctx, &ctx->conninfo->notbefore, |
152 |
|
24 |
&ctx->conninfo->notafter) == -1) |
153 |
|
|
goto err; |
154 |
|
|
|
155 |
|
12 |
return (0); |
156 |
|
|
|
157 |
|
|
err: |
158 |
|
|
return (-1); |
159 |
|
24 |
} |
160 |
|
|
|
161 |
|
|
static int |
162 |
|
|
tls_conninfo_alpn_proto(struct tls *ctx) |
163 |
|
|
{ |
164 |
|
48 |
const unsigned char *p; |
165 |
|
24 |
unsigned int len; |
166 |
|
|
|
167 |
|
24 |
free(ctx->conninfo->alpn); |
168 |
|
24 |
ctx->conninfo->alpn = NULL; |
169 |
|
|
|
170 |
|
24 |
SSL_get0_alpn_selected(ctx->ssl_conn, &p, &len); |
171 |
✗✓ |
24 |
if (len > 0) { |
172 |
|
|
if ((ctx->conninfo->alpn = malloc(len + 1)) == NULL) |
173 |
|
|
return (-1); |
174 |
|
|
memcpy(ctx->conninfo->alpn, p, len); |
175 |
|
|
ctx->conninfo->alpn[len] = '\0'; |
176 |
|
|
} |
177 |
|
|
|
178 |
|
24 |
return (0); |
179 |
|
24 |
} |
180 |
|
|
|
181 |
|
|
static int |
182 |
|
|
tls_conninfo_cert_pem(struct tls *ctx) |
183 |
|
|
{ |
184 |
|
|
int i, rv = -1; |
185 |
|
|
BIO *membio = NULL; |
186 |
|
48 |
BUF_MEM *bptr = NULL; |
187 |
|
|
|
188 |
✓✗ |
24 |
if (ctx->conninfo == NULL) |
189 |
|
|
goto err; |
190 |
✓✓ |
24 |
if (ctx->ssl_peer_cert == NULL) |
191 |
|
12 |
return 0; |
192 |
✓✗ |
12 |
if ((membio = BIO_new(BIO_s_mem()))== NULL) |
193 |
|
|
goto err; |
194 |
|
|
|
195 |
|
|
/* |
196 |
|
|
* We have to write the peer cert out separately, because |
197 |
|
|
* the certificate chain may or may not contain it. |
198 |
|
|
*/ |
199 |
✓✗ |
12 |
if (!PEM_write_bio_X509(membio, ctx->ssl_peer_cert)) |
200 |
|
|
goto err; |
201 |
✓✓ |
48 |
for (i = 0; i < sk_X509_num(ctx->ssl_peer_chain); i++) { |
202 |
|
12 |
X509 *chaincert = sk_X509_value(ctx->ssl_peer_chain, i); |
203 |
✗✓✗✗
|
12 |
if (chaincert != ctx->ssl_peer_cert && |
204 |
|
|
!PEM_write_bio_X509(membio, chaincert)) |
205 |
|
|
goto err; |
206 |
✓✓✓ |
12 |
} |
207 |
|
|
|
208 |
|
12 |
BIO_get_mem_ptr(membio, &bptr); |
209 |
|
12 |
free(ctx->conninfo->peer_cert); |
210 |
|
12 |
ctx->conninfo->peer_cert_len = 0; |
211 |
✓✗ |
12 |
if ((ctx->conninfo->peer_cert = malloc(bptr->length)) == NULL) |
212 |
|
|
goto err; |
213 |
|
12 |
ctx->conninfo->peer_cert_len = bptr->length; |
214 |
|
24 |
memcpy(ctx->conninfo->peer_cert, bptr->data, |
215 |
|
12 |
ctx->conninfo->peer_cert_len); |
216 |
|
|
|
217 |
|
|
/* BIO_free() will kill BUF_MEM - because we have not set BIO_NOCLOSE */ |
218 |
|
12 |
rv = 0; |
219 |
|
|
err: |
220 |
|
12 |
BIO_free(membio); |
221 |
|
12 |
return rv; |
222 |
|
24 |
} |
223 |
|
|
|
224 |
|
|
int |
225 |
|
|
tls_conninfo_populate(struct tls *ctx) |
226 |
|
|
{ |
227 |
|
|
const char *tmp; |
228 |
|
|
|
229 |
|
48 |
tls_conninfo_free(ctx->conninfo); |
230 |
|
|
|
231 |
✗✓ |
24 |
if ((ctx->conninfo = calloc(1, sizeof(struct tls_conninfo))) == NULL) { |
232 |
|
|
tls_set_errorx(ctx, "out of memory"); |
233 |
|
|
goto err; |
234 |
|
|
} |
235 |
|
|
|
236 |
✓✗ |
24 |
if (tls_conninfo_alpn_proto(ctx) == -1) |
237 |
|
|
goto err; |
238 |
|
|
|
239 |
✓✗ |
24 |
if ((tmp = SSL_get_cipher(ctx->ssl_conn)) == NULL) |
240 |
|
|
goto err; |
241 |
|
24 |
ctx->conninfo->cipher = strdup(tmp); |
242 |
✓✗ |
24 |
if (ctx->conninfo->cipher == NULL) |
243 |
|
|
goto err; |
244 |
|
|
|
245 |
✓✗ |
24 |
if (ctx->servername != NULL) { |
246 |
✓✗ |
48 |
if ((ctx->conninfo->servername = |
247 |
|
48 |
strdup(ctx->servername)) == NULL) |
248 |
|
|
goto err; |
249 |
|
|
} |
250 |
|
|
|
251 |
✓✗ |
24 |
if ((tmp = SSL_get_version(ctx->ssl_conn)) == NULL) |
252 |
|
|
goto err; |
253 |
|
24 |
ctx->conninfo->version = strdup(tmp); |
254 |
✓✗ |
24 |
if (ctx->conninfo->version == NULL) |
255 |
|
|
goto err; |
256 |
|
|
|
257 |
✓✗ |
24 |
if (tls_get_peer_cert_info(ctx) == -1) |
258 |
|
|
goto err; |
259 |
|
|
|
260 |
✓✗ |
24 |
if (tls_conninfo_cert_pem(ctx) == -1) |
261 |
|
|
goto err; |
262 |
|
|
|
263 |
|
24 |
return (0); |
264 |
|
|
|
265 |
|
|
err: |
266 |
|
|
tls_conninfo_free(ctx->conninfo); |
267 |
|
|
ctx->conninfo = NULL; |
268 |
|
|
|
269 |
|
|
return (-1); |
270 |
|
24 |
} |
271 |
|
|
|
272 |
|
|
void |
273 |
|
|
tls_conninfo_free(struct tls_conninfo *conninfo) |
274 |
|
|
{ |
275 |
✓✓ |
516 |
if (conninfo == NULL) |
276 |
|
|
return; |
277 |
|
|
|
278 |
|
24 |
free(conninfo->alpn); |
279 |
|
24 |
conninfo->alpn = NULL; |
280 |
|
24 |
free(conninfo->cipher); |
281 |
|
24 |
conninfo->cipher = NULL; |
282 |
|
24 |
free(conninfo->servername); |
283 |
|
24 |
conninfo->servername = NULL; |
284 |
|
24 |
free(conninfo->version); |
285 |
|
24 |
conninfo->version = NULL; |
286 |
|
|
|
287 |
|
24 |
free(conninfo->hash); |
288 |
|
24 |
conninfo->hash = NULL; |
289 |
|
24 |
free(conninfo->issuer); |
290 |
|
24 |
conninfo->issuer = NULL; |
291 |
|
24 |
free(conninfo->subject); |
292 |
|
24 |
conninfo->subject = NULL; |
293 |
|
|
|
294 |
|
24 |
free(conninfo->peer_cert); |
295 |
|
24 |
conninfo->peer_cert = NULL; |
296 |
|
24 |
conninfo->peer_cert_len = 0; |
297 |
|
|
|
298 |
|
24 |
free(conninfo); |
299 |
|
282 |
} |
300 |
|
|
|
301 |
|
|
const char * |
302 |
|
|
tls_conn_alpn_selected(struct tls *ctx) |
303 |
|
|
{ |
304 |
|
|
if (ctx->conninfo == NULL) |
305 |
|
|
return (NULL); |
306 |
|
|
return (ctx->conninfo->alpn); |
307 |
|
|
} |
308 |
|
|
|
309 |
|
|
const char * |
310 |
|
|
tls_conn_cipher(struct tls *ctx) |
311 |
|
|
{ |
312 |
|
|
if (ctx->conninfo == NULL) |
313 |
|
|
return (NULL); |
314 |
|
|
return (ctx->conninfo->cipher); |
315 |
|
|
} |
316 |
|
|
|
317 |
|
|
const char * |
318 |
|
|
tls_conn_servername(struct tls *ctx) |
319 |
|
|
{ |
320 |
|
|
if (ctx->conninfo == NULL) |
321 |
|
|
return (NULL); |
322 |
|
|
return (ctx->conninfo->servername); |
323 |
|
|
} |
324 |
|
|
|
325 |
|
|
const char * |
326 |
|
|
tls_conn_version(struct tls *ctx) |
327 |
|
|
{ |
328 |
|
|
if (ctx->conninfo == NULL) |
329 |
|
|
return (NULL); |
330 |
|
|
return (ctx->conninfo->version); |
331 |
|
|
} |
332 |
|
|
|