OLD | NEW |
| (Empty) |
1 /* Licensed to the Apache Software Foundation (ASF) under one or more | |
2 * contributor license agreements. See the NOTICE file distributed with | |
3 * this work for additional information regarding copyright ownership. | |
4 * The ASF licenses this file to You under the Apache License, Version 2.0 | |
5 * (the "License"); you may not use this file except in compliance with | |
6 * the License. You may obtain a copy of the License at | |
7 * | |
8 * http://www.apache.org/licenses/LICENSE-2.0 | |
9 * | |
10 * Unless required by applicable law or agreed to in writing, software | |
11 * distributed under the License is distributed on an "AS IS" BASIS, | |
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 * See the License for the specific language governing permissions and | |
14 * limitations under the License. | |
15 */ | |
16 | |
17 /** SSL info wrapper | |
18 * | |
19 * @author Mladen Turk | |
20 * @version $Id: sslinfo.c 1658603 2015-02-09 23:26:44Z kkolinko $ | |
21 */ | |
22 | |
23 #include "tcn.h" | |
24 #include "apr_file_io.h" | |
25 #include "apr_thread_mutex.h" | |
26 #include "apr_poll.h" | |
27 | |
28 #ifdef HAVE_OPENSSL | |
29 #include "ssl_private.h" | |
30 | |
31 static const char *hex_basis = "0123456789ABCDEF"; | |
32 | |
33 static char *convert_to_hex(const void *buf, size_t len) | |
34 { | |
35 const unsigned char *p = ( const unsigned char *)buf; | |
36 char *str, *s; | |
37 size_t i; | |
38 | |
39 if ((len < 1) || ((str = malloc(len * 2 + 1)) == NULL)) | |
40 return NULL; | |
41 for (i = 0, s = str; i < len; i++) { | |
42 unsigned char c = *p++; | |
43 *s++ = hex_basis[c >> 4]; | |
44 *s++ = hex_basis[c & 0x0F]; | |
45 } | |
46 *s = '\0'; | |
47 return str; | |
48 } | |
49 | |
50 #define DIGIT2NUM(x) (((x)[0] - '0') * 10 + (x)[1] - '0') | |
51 | |
52 static int get_days_remaining(ASN1_UTCTIME *tm) | |
53 { | |
54 apr_time_t then, now = apr_time_now(); | |
55 apr_time_exp_t exp = {0}; | |
56 int diff; | |
57 | |
58 /* Fail if the time isn't a valid ASN.1 UTCTIME; RFC3280 mandates | |
59 * that the seconds digits are present even though ASN.1 | |
60 * doesn't. */ | |
61 if (tm->length < 11 || !ASN1_UTCTIME_check(tm)) | |
62 return 0; | |
63 | |
64 exp.tm_year = DIGIT2NUM(tm->data); | |
65 exp.tm_mon = DIGIT2NUM(tm->data + 2) - 1; | |
66 exp.tm_mday = DIGIT2NUM(tm->data + 4) + 1; | |
67 exp.tm_hour = DIGIT2NUM(tm->data + 6); | |
68 exp.tm_min = DIGIT2NUM(tm->data + 8); | |
69 exp.tm_sec = DIGIT2NUM(tm->data + 10); | |
70 | |
71 if (exp.tm_year <= 50) | |
72 exp.tm_year += 100; | |
73 if (apr_time_exp_gmt_get(&then, &exp) != APR_SUCCESS) | |
74 return 0; | |
75 | |
76 diff = (int)((apr_time_sec(then) - apr_time_sec(now)) / (60*60*24)); | |
77 return diff > 0 ? diff : 0; | |
78 } | |
79 | |
80 static char *get_cert_valid(ASN1_UTCTIME *tm) | |
81 { | |
82 char *result; | |
83 BIO* bio; | |
84 int n; | |
85 | |
86 if ((bio = BIO_new(BIO_s_mem())) == NULL) | |
87 return NULL; | |
88 ASN1_UTCTIME_print(bio, tm); | |
89 n = BIO_pending(bio); | |
90 result = malloc(n+1); | |
91 n = BIO_read(bio, result, n); | |
92 result[n] = '\0'; | |
93 BIO_free(bio); | |
94 return result; | |
95 } | |
96 | |
97 static char *get_cert_PEM(X509 *xs) | |
98 { | |
99 char *result = NULL; | |
100 BIO *bio; | |
101 | |
102 if ((bio = BIO_new(BIO_s_mem())) == NULL) | |
103 return NULL; | |
104 if (PEM_write_bio_X509(bio, xs)) { | |
105 int n = BIO_pending(bio); | |
106 result = malloc(n+1); | |
107 n = BIO_read(bio, result, n); | |
108 result[n] = '\0'; | |
109 } | |
110 BIO_free(bio); | |
111 return result; | |
112 } | |
113 | |
114 static unsigned char *get_cert_ASN1(X509 *xs, int *len) | |
115 { | |
116 unsigned char *result = NULL; | |
117 BIO *bio; | |
118 | |
119 *len = 0; | |
120 if ((bio = BIO_new(BIO_s_mem())) == NULL) | |
121 return NULL; | |
122 if (i2d_X509_bio(bio, xs)) { | |
123 int n = BIO_pending(bio); | |
124 result = malloc(n); | |
125 n = BIO_read(bio, result, n); | |
126 *len = n; | |
127 } | |
128 BIO_free(bio); | |
129 return result; | |
130 } | |
131 | |
132 | |
133 static char *get_cert_serial(X509 *xs) | |
134 { | |
135 char *result; | |
136 BIO *bio; | |
137 int n; | |
138 | |
139 if ((bio = BIO_new(BIO_s_mem())) == NULL) | |
140 return NULL; | |
141 i2a_ASN1_INTEGER(bio, X509_get_serialNumber(xs)); | |
142 n = BIO_pending(bio); | |
143 result = malloc(n+1); | |
144 n = BIO_read(bio, result, n); | |
145 result[n] = '\0'; | |
146 BIO_free(bio); | |
147 return result; | |
148 } | |
149 | |
150 static const struct { | |
151 int fid; | |
152 int nid; | |
153 } info_cert_dn_rec[] = { | |
154 { SSL_INFO_DN_COUNTRYNAME, NID_countryName }, | |
155 { SSL_INFO_DN_STATEORPROVINCENAME, NID_stateOrProvinceName }, | |
156 { SSL_INFO_DN_LOCALITYNAME, NID_localityName }, | |
157 { SSL_INFO_DN_ORGANIZATIONNAME, NID_organizationName }, | |
158 { SSL_INFO_DN_ORGANIZATIONALUNITNAME, NID_organizationalUnitName }, | |
159 { SSL_INFO_DN_COMMONNAME, NID_commonName }, | |
160 { SSL_INFO_DN_TITLE, NID_title }, | |
161 { SSL_INFO_DN_INITIALS, NID_initials }, | |
162 { SSL_INFO_DN_GIVENNAME, NID_givenName }, | |
163 { SSL_INFO_DN_SURNAME, NID_surname }, | |
164 { SSL_INFO_DN_DESCRIPTION, NID_description }, | |
165 { SSL_INFO_DN_UNIQUEIDENTIFIER, NID_x500UniqueIdentifier }, | |
166 { SSL_INFO_DN_EMAILADDRESS, NID_pkcs9_emailAddress }, | |
167 { 0, 0 } | |
168 }; | |
169 | |
170 static char *lookup_ssl_cert_dn(X509_NAME *xsname, int dnidx) | |
171 { | |
172 char *result; | |
173 X509_NAME_ENTRY *xsne; | |
174 int i, j, n, idx = 0; | |
175 | |
176 result = NULL; | |
177 | |
178 for (i = 0; info_cert_dn_rec[i].fid != 0; i++) { | |
179 if (info_cert_dn_rec[i].fid == dnidx) { | |
180 for (j = 0; j < sk_X509_NAME_ENTRY_num((STACK_OF(X509_NAME_ENTRY) *) | |
181 (xsname->entries)); j++) { | |
182 xsne = sk_X509_NAME_ENTRY_value((STACK_OF(X509_NAME_ENTRY) *) | |
183 (xsname->entries), j); | |
184 | |
185 n =OBJ_obj2nid((ASN1_OBJECT *)X509_NAME_ENTRY_get_object(xsne)); | |
186 if (n == info_cert_dn_rec[i].nid && idx-- == 0) { | |
187 result = malloc(xsne->value->length + 1); | |
188 memcpy(result, xsne->value->data, | |
189 xsne->value->length); | |
190 result[xsne->value->length] = '\0'; | |
191 | |
192 #if APR_CHARSET_EBCDIC | |
193 ap_xlate_proto_from_ascii(result, xsne->value->length); | |
194 #endif /* APR_CHARSET_EBCDIC */ | |
195 break; | |
196 } | |
197 } | |
198 break; | |
199 } | |
200 } | |
201 return result; | |
202 } | |
203 | |
204 TCN_IMPLEMENT_CALL(jobject, SSLSocket, getInfoB)(TCN_STDARGS, jlong sock, | |
205 jint what) | |
206 { | |
207 tcn_socket_t *a = J2P(sock, tcn_socket_t *); | |
208 tcn_ssl_conn_t *s; | |
209 jbyteArray array = NULL; | |
210 apr_status_t rv = APR_SUCCESS; | |
211 | |
212 UNREFERENCED(o); | |
213 TCN_ASSERT(sock != 0); | |
214 | |
215 s = (tcn_ssl_conn_t *)(a->opaque); | |
216 switch (what) { | |
217 case SSL_INFO_SESSION_ID: | |
218 { | |
219 SSL_SESSION *session = SSL_get_session(s->ssl); | |
220 if (session) { | |
221 unsigned int len; | |
222 const unsigned char *id = SSL_SESSION_get_id(session, &len); | |
223 array = tcn_new_arrayb(e, id, len); | |
224 } | |
225 } | |
226 break; | |
227 default: | |
228 rv = APR_EINVAL; | |
229 break; | |
230 } | |
231 if (what & SSL_INFO_CLIENT_MASK) { | |
232 X509 *xs; | |
233 unsigned char *result; | |
234 int len; | |
235 if ((xs = SSL_get_peer_certificate(s->ssl)) != NULL) { | |
236 switch (what) { | |
237 case SSL_INFO_CLIENT_CERT: | |
238 if ((result = get_cert_ASN1(xs, &len))) { | |
239 array = tcn_new_arrayb(e, result, len); | |
240 free(result); | |
241 } | |
242 break; | |
243 } | |
244 X509_free(xs); | |
245 } | |
246 rv = APR_SUCCESS; | |
247 } | |
248 else if (what & SSL_INFO_SERVER_MASK) { | |
249 X509 *xs; | |
250 unsigned char *result; | |
251 int len; | |
252 if ((xs = SSL_get_certificate(s->ssl)) != NULL) { | |
253 switch (what) { | |
254 case SSL_INFO_SERVER_CERT: | |
255 if ((result = get_cert_ASN1(xs, &len))) { | |
256 array = tcn_new_arrayb(e, result, len); | |
257 free(result); | |
258 } | |
259 break; | |
260 } | |
261 /* XXX: No need to call the X509_free(xs); */ | |
262 } | |
263 rv = APR_SUCCESS; | |
264 } | |
265 else if (what & SSL_INFO_CLIENT_CERT_CHAIN) { | |
266 X509 *xs; | |
267 unsigned char *result; | |
268 STACK_OF(X509) *sk = SSL_get_peer_cert_chain(s->ssl); | |
269 int len, n = what & 0x0F; | |
270 if (n < sk_X509_num(sk)) { | |
271 xs = sk_X509_value(sk, n); | |
272 if ((result = get_cert_ASN1(xs, &len))) { | |
273 array = tcn_new_arrayb(e, result, len); | |
274 free(result); | |
275 } | |
276 } | |
277 rv = APR_SUCCESS; | |
278 } | |
279 if (rv != APR_SUCCESS) | |
280 tcn_ThrowAPRException(e, rv); | |
281 | |
282 return array; | |
283 } | |
284 | |
285 TCN_IMPLEMENT_CALL(jstring, SSLSocket, getInfoS)(TCN_STDARGS, jlong sock, | |
286 jint what) | |
287 { | |
288 tcn_socket_t *a = J2P(sock, tcn_socket_t *); | |
289 tcn_ssl_conn_t *s; | |
290 jstring value = NULL; | |
291 apr_status_t rv = APR_SUCCESS; | |
292 | |
293 UNREFERENCED(o); | |
294 TCN_ASSERT(sock != 0); | |
295 | |
296 s = (tcn_ssl_conn_t *)(a->opaque); | |
297 switch (what) { | |
298 case SSL_INFO_SESSION_ID: | |
299 { | |
300 SSL_SESSION *session = SSL_get_session(s->ssl); | |
301 if (session) { | |
302 unsigned int len; | |
303 const unsigned char *id = SSL_SESSION_get_id(session, &len); | |
304 char *hs = convert_to_hex(id, len); | |
305 if (hs) { | |
306 value = tcn_new_string(e, hs); | |
307 free(hs); | |
308 } | |
309 } | |
310 } | |
311 break; | |
312 case SSL_INFO_PROTOCOL: | |
313 value = tcn_new_string(e, SSL_get_version(s->ssl)); | |
314 break; | |
315 case SSL_INFO_CIPHER: | |
316 value = tcn_new_string(e, SSL_get_cipher_name(s->ssl)); | |
317 break; | |
318 case SSL_INFO_CIPHER_VERSION: | |
319 value = tcn_new_string(e, SSL_get_cipher_version(s->ssl)); | |
320 break; | |
321 case SSL_INFO_CIPHER_DESCRIPTION: | |
322 { | |
323 SSL_CIPHER *cipher = (SSL_CIPHER *)SSL_get_current_cipher(s->ssl
); | |
324 if (cipher) { | |
325 char buf[256]; | |
326 const char *desc = SSL_CIPHER_description(cipher, buf, 256); | |
327 value = tcn_new_string(e, desc); | |
328 } | |
329 } | |
330 break; | |
331 default: | |
332 rv = APR_EINVAL; | |
333 break; | |
334 } | |
335 if (what & (SSL_INFO_CLIENT_S_DN | SSL_INFO_CLIENT_I_DN)) { | |
336 X509 *xs; | |
337 X509_NAME *xsname; | |
338 if ((xs = SSL_get_peer_certificate(s->ssl)) != NULL) { | |
339 char *result; | |
340 int idx = what & 0x0F; | |
341 if (what & SSL_INFO_CLIENT_S_DN) | |
342 xsname = X509_get_subject_name(xs); | |
343 else | |
344 xsname = X509_get_issuer_name(xs); | |
345 if (idx) { | |
346 result = lookup_ssl_cert_dn(xsname, idx); | |
347 if (result) { | |
348 value = tcn_new_string(e, result); | |
349 free(result); | |
350 } | |
351 } | |
352 else | |
353 value = tcn_new_string(e, X509_NAME_oneline(xsname, NULL, 0)); | |
354 X509_free(xs); | |
355 } | |
356 rv = APR_SUCCESS; | |
357 } | |
358 else if (what & (SSL_INFO_SERVER_S_DN | SSL_INFO_SERVER_I_DN)) { | |
359 X509 *xs; | |
360 X509_NAME *xsname; | |
361 if ((xs = SSL_get_certificate(s->ssl)) != NULL) { | |
362 char *result; | |
363 int idx = what & 0x0F; | |
364 if (what & SSL_INFO_SERVER_S_DN) | |
365 xsname = X509_get_subject_name(xs); | |
366 else | |
367 xsname = X509_get_issuer_name(xs); | |
368 if (idx) { | |
369 result = lookup_ssl_cert_dn(xsname, what & 0x0F); | |
370 if (result) { | |
371 value = tcn_new_string(e, result); | |
372 free(result); | |
373 } | |
374 } | |
375 else | |
376 value = tcn_new_string(e, X509_NAME_oneline(xsname, NULL, 0)); | |
377 /* XXX: No need to call the X509_free(xs); */ | |
378 } | |
379 rv = APR_SUCCESS; | |
380 } | |
381 else if (what & SSL_INFO_CLIENT_MASK) { | |
382 X509 *xs; | |
383 char *result; | |
384 int nid; | |
385 if ((xs = SSL_get_peer_certificate(s->ssl)) != NULL) { | |
386 switch (what) { | |
387 case SSL_INFO_CLIENT_V_START: | |
388 if ((result = get_cert_valid(X509_get_notBefore(xs)))) { | |
389 value = tcn_new_string(e, result); | |
390 free(result); | |
391 } | |
392 break; | |
393 case SSL_INFO_CLIENT_V_END: | |
394 if ((result = get_cert_valid(X509_get_notAfter(xs)))) { | |
395 value = tcn_new_string(e, result); | |
396 free(result); | |
397 } | |
398 break; | |
399 case SSL_INFO_CLIENT_A_SIG: | |
400 nid = OBJ_obj2nid((ASN1_OBJECT *)xs->cert_info->signature->a
lgorithm); | |
401 if (nid == NID_undef) | |
402 value = tcn_new_string(e, "UNKNOWN"); | |
403 else | |
404 value = tcn_new_string(e, OBJ_nid2ln(nid)); | |
405 break; | |
406 case SSL_INFO_CLIENT_A_KEY: | |
407 nid = OBJ_obj2nid((ASN1_OBJECT *)xs->cert_info->key->algor->
algorithm); | |
408 if (nid == NID_undef) | |
409 value = tcn_new_string(e, "UNKNOWN"); | |
410 else | |
411 value = tcn_new_string(e, OBJ_nid2ln(nid)); | |
412 break; | |
413 case SSL_INFO_CLIENT_CERT: | |
414 if ((result = get_cert_PEM(xs))) { | |
415 value = tcn_new_string(e, result); | |
416 free(result); | |
417 } | |
418 break; | |
419 case SSL_INFO_CLIENT_M_SERIAL: | |
420 if ((result = get_cert_serial(xs))) { | |
421 value = tcn_new_string(e, result); | |
422 free(result); | |
423 } | |
424 break; | |
425 } | |
426 X509_free(xs); | |
427 } | |
428 rv = APR_SUCCESS; | |
429 } | |
430 else if (what & SSL_INFO_SERVER_MASK) { | |
431 X509 *xs; | |
432 char *result; | |
433 int nid; | |
434 if ((xs = SSL_get_certificate(s->ssl)) != NULL) { | |
435 switch (what) { | |
436 case SSL_INFO_SERVER_V_START: | |
437 if ((result = get_cert_valid(X509_get_notBefore(xs)))) { | |
438 value = tcn_new_string(e, result); | |
439 free(result); | |
440 } | |
441 break; | |
442 case SSL_INFO_SERVER_V_END: | |
443 if ((result = get_cert_valid(X509_get_notAfter(xs)))) { | |
444 value = tcn_new_string(e, result); | |
445 free(result); | |
446 } | |
447 break; | |
448 case SSL_INFO_SERVER_A_SIG: | |
449 nid = OBJ_obj2nid((ASN1_OBJECT *)xs->cert_info->signature->a
lgorithm); | |
450 if (nid == NID_undef) | |
451 value = tcn_new_string(e, "UNKNOWN"); | |
452 else | |
453 value = tcn_new_string(e, OBJ_nid2ln(nid)); | |
454 break; | |
455 case SSL_INFO_SERVER_A_KEY: | |
456 nid = OBJ_obj2nid((ASN1_OBJECT *)xs->cert_info->key->algor->
algorithm); | |
457 if (nid == NID_undef) | |
458 value = tcn_new_string(e, "UNKNOWN"); | |
459 else | |
460 value = tcn_new_string(e, OBJ_nid2ln(nid)); | |
461 break; | |
462 case SSL_INFO_SERVER_CERT: | |
463 if ((result = get_cert_PEM(xs))) { | |
464 value = tcn_new_string(e, result); | |
465 free(result); | |
466 } | |
467 break; | |
468 case SSL_INFO_SERVER_M_SERIAL: | |
469 if ((result = get_cert_serial(xs))) { | |
470 value = tcn_new_string(e, result); | |
471 free(result); | |
472 } | |
473 break; | |
474 } | |
475 /* XXX: No need to call the X509_free(xs); */ | |
476 } | |
477 rv = APR_SUCCESS; | |
478 } | |
479 else if (what & SSL_INFO_CLIENT_CERT_CHAIN) { | |
480 X509 *xs; | |
481 char *result; | |
482 STACK_OF(X509) *sk = SSL_get_peer_cert_chain(s->ssl); | |
483 int n = what & 0x0F; | |
484 if (n < sk_X509_num(sk)) { | |
485 xs = sk_X509_value(sk, n); | |
486 if ((result = get_cert_PEM(xs))) { | |
487 value = tcn_new_string(e, result); | |
488 free(result); | |
489 } | |
490 } | |
491 rv = APR_SUCCESS; | |
492 } | |
493 if (rv != APR_SUCCESS) | |
494 tcn_ThrowAPRException(e, rv); | |
495 | |
496 return value; | |
497 } | |
498 | |
499 TCN_IMPLEMENT_CALL(jint, SSLSocket, getInfoI)(TCN_STDARGS, jlong sock, | |
500 jint what) | |
501 { | |
502 tcn_socket_t *a = J2P(sock, tcn_socket_t *); | |
503 tcn_ssl_conn_t *s; | |
504 apr_status_t rv = APR_SUCCESS; | |
505 jint value = -1; | |
506 | |
507 UNREFERENCED(o); | |
508 TCN_ASSERT(sock != 0); | |
509 | |
510 s = (tcn_ssl_conn_t *)(a->opaque); | |
511 | |
512 switch (what) { | |
513 case SSL_INFO_CIPHER_USEKEYSIZE: | |
514 case SSL_INFO_CIPHER_ALGKEYSIZE: | |
515 { | |
516 int usekeysize = 0; | |
517 int algkeysize = 0; | |
518 const SSL_CIPHER *cipher = SSL_get_current_cipher(s->ssl); | |
519 if (cipher) { | |
520 usekeysize = SSL_CIPHER_get_bits(cipher, &algkeysize); | |
521 if (what == SSL_INFO_CIPHER_USEKEYSIZE) | |
522 value = usekeysize; | |
523 else | |
524 value = algkeysize; | |
525 } | |
526 } | |
527 break; | |
528 case SSL_INFO_CLIENT_CERT_CHAIN: | |
529 { | |
530 STACK_OF(X509) *sk = SSL_get_peer_cert_chain(s->ssl); | |
531 value = sk_X509_num(sk); | |
532 } | |
533 break; | |
534 default: | |
535 rv = APR_EINVAL; | |
536 break; | |
537 } | |
538 if (what & SSL_INFO_CLIENT_MASK) { | |
539 X509 *xs; | |
540 if ((xs = SSL_get_peer_certificate(s->ssl)) != NULL) { | |
541 switch (what) { | |
542 case SSL_INFO_CLIENT_V_REMAIN: | |
543 value = get_days_remaining(X509_get_notAfter(xs)); | |
544 rv = APR_SUCCESS; | |
545 break; | |
546 default: | |
547 rv = APR_EINVAL; | |
548 break; | |
549 } | |
550 X509_free(xs); | |
551 } | |
552 } | |
553 | |
554 if (rv != APR_SUCCESS) | |
555 tcn_ThrowAPRException(e, rv); | |
556 return value; | |
557 } | |
558 | |
559 #else | |
560 /* OpenSSL is not supported. | |
561 * Create empty stubs. | |
562 */ | |
563 | |
564 TCN_IMPLEMENT_CALL(jobject, SSLSocket, getInfoB)(TCN_STDARGS, jlong sock, | |
565 jint what) | |
566 { | |
567 UNREFERENCED_STDARGS; | |
568 UNREFERENCED(sock); | |
569 UNREFERENCED(what); | |
570 return NULL; | |
571 } | |
572 | |
573 TCN_IMPLEMENT_CALL(jstring, SSLSocket, getInfoS)(TCN_STDARGS, jlong sock, | |
574 jint what) | |
575 { | |
576 UNREFERENCED_STDARGS; | |
577 UNREFERENCED(sock); | |
578 UNREFERENCED(what); | |
579 return NULL; | |
580 } | |
581 | |
582 TCN_IMPLEMENT_CALL(jint, SSLSocket, getInfoI)(TCN_STDARGS, jlong sock, | |
583 jint what) | |
584 { | |
585 UNREFERENCED_STDARGS; | |
586 UNREFERENCED(sock); | |
587 UNREFERENCED(what); | |
588 return 0; | |
589 } | |
590 | |
591 #endif | |
OLD | NEW |