1 /* GnuTLS --- Guile bindings for GnuTLS.
2 Copyright (C) 2007-2014, 2016, 2019 Free Software Foundation, Inc.
3
4 GnuTLS is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 GnuTLS is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with GnuTLS; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
17
18 /* Written by Ludovic Courtès <ludo@gnu.org>. */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <stdio.h>
25 #include <stdint.h>
26 #include <string.h>
27 #include <gnutls/gnutls.h>
28 #include <gnutls/openpgp.h>
29 #include <libguile.h>
30
31 #include <alloca.h>
32 #include <assert.h>
33
34 #include "enums.h"
35 #include "smobs.h"
36 #include "errors.h"
37 #include "utils.h"
38
39
40 #ifndef HAVE_SCM_GC_MALLOC_POINTERLESS
41 # define scm_gc_malloc_pointerless scm_gc_malloc
42 #endif
43
44 /* Maximum size allowed for 'alloca'. */
45 #define ALLOCA_MAX_SIZE 1024U
46
47 /* Allocate SIZE bytes, either on the C stack or on the GC-managed heap. */
48 #define FAST_ALLOC(size) \
49 (((size) <= ALLOCA_MAX_SIZE) \
50 ? alloca (size) \
51 : scm_gc_malloc_pointerless ((size), "gnutls-alloc"))
52
53 /* SMOB and enums type definitions. */
54 #include "enum-map.i.c"
55 #include "smob-types.i.c"
56
57 const char scm_gnutls_array_error_message[] =
58 "cannot handle non-contiguous array: ~A";
59
60
61 /* Data that are attached to `gnutls_session_t' objects.
62
63 We need to keep several pieces of information along with each session:
64
65 - A boolean indicating whether its underlying transport is a file
66 descriptor or Scheme port. This is used to decide whether to leave
67 "Guile mode" when invoking `gnutls_record_recv ()'.
68
69 - The record port attached to the session (returned by
70 `session-record-port'). This is so that several calls to
71 `session-record-port' return the same port.
72
73 Currently, this information is maintained into a pair. The whole pair is
74 marked by the session mark procedure. */
75
76 #define SCM_GNUTLS_MAKE_SESSION_DATA() \
77 scm_cons (SCM_BOOL_F, SCM_BOOL_F)
78 #define SCM_GNUTLS_SET_SESSION_DATA(c_session, data) \
79 gnutls_session_set_ptr (c_session, (void *) SCM_UNPACK (data))
80 #define SCM_GNUTLS_SESSION_DATA(c_session) \
81 SCM_PACK ((scm_t_bits) gnutls_session_get_ptr (c_session))
82
83 #define SCM_GNUTLS_SET_SESSION_TRANSPORT_IS_FD(c_session, c_is_fd) \
84 SCM_SETCAR (SCM_GNUTLS_SESSION_DATA (c_session), \
85 scm_from_bool (c_is_fd))
86 #define SCM_GNUTLS_SET_SESSION_RECORD_PORT(c_session, port) \
87 SCM_SETCDR (SCM_GNUTLS_SESSION_DATA (c_session), port)
88
89 #define SCM_GNUTLS_SESSION_TRANSPORT_IS_FD(c_session) \
90 scm_to_bool (SCM_CAR (SCM_GNUTLS_SESSION_DATA (c_session)))
91 #define SCM_GNUTLS_SESSION_RECORD_PORT(c_session) \
92 SCM_CDR (SCM_GNUTLS_SESSION_DATA (c_session))
93
94
95 /* Weak-key hash table. */
96 static SCM weak_refs;
97
98 /* Register a weak reference from @FROM to @TO, such that the lifetime of TO is
99 greater than or equal to that of FROM. */
100 static void
register_weak_reference(SCM from,SCM to)101 register_weak_reference (SCM from, SCM to)
102 {
103 scm_hashq_set_x (weak_refs, from, to);
104 }
105
106
107
108
109 /* Bindings. */
110
111 /* Mark the data associated with SESSION. */
SCM_SMOB_MARK(scm_tc16_gnutls_session,mark_session,session)112 SCM_SMOB_MARK (scm_tc16_gnutls_session, mark_session, session)
113 {
114 gnutls_session_t c_session;
115
116 c_session = scm_to_gnutls_session (session, 1, "mark_session");
117
118 return (SCM_GNUTLS_SESSION_DATA (c_session));
119 }
120
121 SCM_DEFINE (scm_gnutls_version, "gnutls-version", 0, 0, 0,
122 (void),
123 "Return a string denoting the version number of the underlying "
124 "GnuTLS library, e.g., @code{\"1.7.2\"}.")
125 #define FUNC_NAME s_scm_gnutls_version
126 {
127 return (scm_from_locale_string (gnutls_check_version (NULL)));
128 }
129
130 #undef FUNC_NAME
131
132 SCM_DEFINE (scm_gnutls_make_session, "make-session", 1, 0, 1,
133 (SCM end, SCM flags),
134 "Return a new session for connection end @var{end}, either "
135 "@code{connection-end/server} or @code{connection-end/client}. "
136 "The optional @var{flags} arguments are @code{connection-flag} "
137 "values such as @code{connection-flag/auto-reauth}.")
138 #define FUNC_NAME s_scm_gnutls_make_session
139 {
140 int err, i;
141 gnutls_session_t c_session;
142 gnutls_connection_end_t c_end;
143 gnutls_init_flags_t c_flags = 0;
144 SCM session_data;
145
146 c_end = scm_to_gnutls_connection_end (end, 1, FUNC_NAME);
147
148 session_data = SCM_GNUTLS_MAKE_SESSION_DATA ();
149 for (i = 2; scm_is_pair (flags); flags = scm_cdr (flags), i++)
150 c_flags |= scm_to_gnutls_connection_flag (scm_car (flags), i, FUNC_NAME);
151
152 err = gnutls_init (&c_session, c_end | c_flags);
153
154 if (EXPECT_FALSE (err))
155 scm_gnutls_error (err, FUNC_NAME);
156
157 SCM_GNUTLS_SET_SESSION_DATA (c_session, session_data);
158
159 return (scm_from_gnutls_session (c_session));
160 }
161
162 #undef FUNC_NAME
163
164 SCM_DEFINE (scm_gnutls_bye, "bye", 2, 0, 0,
165 (SCM session, SCM how),
166 "Close @var{session} according to @var{how}.")
167 #define FUNC_NAME s_scm_gnutls_bye
168 {
169 int err;
170 gnutls_session_t c_session;
171 gnutls_close_request_t c_how;
172
173 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
174 c_how = scm_to_gnutls_close_request (how, 2, FUNC_NAME);
175
176 err = gnutls_bye (c_session, c_how);
177 if (EXPECT_FALSE (err))
178 scm_gnutls_error (err, FUNC_NAME);
179
180 return SCM_UNSPECIFIED;
181 }
182
183 #undef FUNC_NAME
184
185 SCM_DEFINE (scm_gnutls_handshake, "handshake", 1, 0, 0,
186 (SCM session), "Perform a handshake for @var{session}.")
187 #define FUNC_NAME s_scm_gnutls_handshake
188 {
189 int err;
190 gnutls_session_t c_session;
191
192 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
193
194 err = gnutls_handshake (c_session);
195 if (EXPECT_FALSE (err))
196 scm_gnutls_error (err, FUNC_NAME);
197
198 return SCM_UNSPECIFIED;
199 }
200
201 #undef FUNC_NAME
202
203 SCM_DEFINE (scm_gnutls_rehandshake, "rehandshake", 1, 0, 0,
204 (SCM session), "Perform a re-handshaking for @var{session}.")
205 #define FUNC_NAME s_scm_gnutls_rehandshake
206 {
207 int err;
208 gnutls_session_t c_session;
209
210 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
211
212 err = gnutls_rehandshake (c_session);
213 if (EXPECT_FALSE (err))
214 scm_gnutls_error (err, FUNC_NAME);
215
216 return SCM_UNSPECIFIED;
217 }
218 #undef FUNC_NAME
219
220 SCM_DEFINE (scm_gnutls_reauthenticate, "reauthenticate", 1, 0, 0,
221 (SCM session), "Perform a re-authentication step for @var{session}.")
222 #define FUNC_NAME s_scm_gnutls_reauthenticate
223 {
224 int err;
225 gnutls_session_t c_session;
226
227 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
228
229 /* FIXME: Allow flags as an argument. */
230 err = gnutls_reauth (c_session, 0);
231 if (EXPECT_FALSE (err))
232 scm_gnutls_error (err, FUNC_NAME);
233
234 return SCM_UNSPECIFIED;
235 }
236 #undef FUNC_NAME
237
238 SCM_DEFINE (scm_gnutls_alert_get, "alert-get", 1, 0, 0,
239 (SCM session), "Get an aleter from @var{session}.")
240 #define FUNC_NAME s_scm_gnutls_alert_get
241 {
242 gnutls_session_t c_session;
243 gnutls_alert_description_t c_alert;
244
245 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
246
247 c_alert = gnutls_alert_get (c_session);
248
249 return (scm_from_gnutls_alert_description (c_alert));
250 }
251
252 #undef FUNC_NAME
253
254 SCM_DEFINE (scm_gnutls_alert_send, "alert-send", 3, 0, 0,
255 (SCM session, SCM level, SCM alert),
256 "Send @var{alert} via @var{session}.")
257 #define FUNC_NAME s_scm_gnutls_alert_send
258 {
259 int err;
260 gnutls_session_t c_session;
261 gnutls_alert_level_t c_level;
262 gnutls_alert_description_t c_alert;
263
264 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
265 c_level = scm_to_gnutls_alert_level (level, 2, FUNC_NAME);
266 c_alert = scm_to_gnutls_alert_description (alert, 3, FUNC_NAME);
267
268 err = gnutls_alert_send (c_session, c_level, c_alert);
269 if (EXPECT_FALSE (err))
270 scm_gnutls_error (err, FUNC_NAME);
271
272 return SCM_UNSPECIFIED;
273 }
274
275 #undef FUNC_NAME
276
277 /* FIXME: Omitting `alert-send-appropriate'. */
278
279
280 /* Session accessors. */
281
282 SCM_DEFINE (scm_gnutls_session_cipher, "session-cipher", 1, 0, 0,
283 (SCM session), "Return @var{session}'s cipher.")
284 #define FUNC_NAME s_scm_gnutls_session_cipher
285 {
286 gnutls_session_t c_session;
287 gnutls_cipher_algorithm_t c_cipher;
288
289 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
290
291 c_cipher = gnutls_cipher_get (c_session);
292
293 return (scm_from_gnutls_cipher (c_cipher));
294 }
295
296 #undef FUNC_NAME
297
298 SCM_DEFINE (scm_gnutls_session_kx, "session-kx", 1, 0, 0,
299 (SCM session), "Return @var{session}'s kx.")
300 #define FUNC_NAME s_scm_gnutls_session_kx
301 {
302 gnutls_session_t c_session;
303 gnutls_kx_algorithm_t c_kx;
304
305 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
306
307 c_kx = gnutls_kx_get (c_session);
308
309 return (scm_from_gnutls_kx (c_kx));
310 }
311
312 #undef FUNC_NAME
313
314 SCM_DEFINE (scm_gnutls_session_mac, "session-mac", 1, 0, 0,
315 (SCM session), "Return @var{session}'s MAC.")
316 #define FUNC_NAME s_scm_gnutls_session_mac
317 {
318 gnutls_session_t c_session;
319 gnutls_mac_algorithm_t c_mac;
320
321 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
322
323 c_mac = gnutls_mac_get (c_session);
324
325 return (scm_from_gnutls_mac (c_mac));
326 }
327
328 #undef FUNC_NAME
329
330 SCM_DEFINE (scm_gnutls_session_compression_method,
331 "session-compression-method", 1, 0, 0,
332 (SCM session), "Return @var{session}'s compression method.")
333 #define FUNC_NAME s_scm_gnutls_session_compression_method
334 {
335 gnutls_session_t c_session;
336 gnutls_compression_method_t c_comp;
337
338 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
339
340 c_comp = gnutls_compression_get (c_session);
341
342 return (scm_from_gnutls_compression_method (c_comp));
343 }
344
345 #undef FUNC_NAME
346
347 SCM_DEFINE (scm_gnutls_session_certificate_type,
348 "session-certificate-type", 1, 0, 0,
349 (SCM session), "Return @var{session}'s certificate type.")
350 #define FUNC_NAME s_scm_gnutls_session_certificate_type
351 {
352 gnutls_session_t c_session;
353 gnutls_certificate_type_t c_cert;
354
355 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
356
357 c_cert = gnutls_certificate_type_get (c_session);
358
359 return (scm_from_gnutls_certificate_type (c_cert));
360 }
361
362 #undef FUNC_NAME
363
364 SCM_DEFINE (scm_gnutls_session_protocol, "session-protocol", 1, 0, 0,
365 (SCM session), "Return the protocol used by @var{session}.")
366 #define FUNC_NAME s_scm_gnutls_session_protocol
367 {
368 gnutls_session_t c_session;
369 gnutls_protocol_t c_protocol;
370
371 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
372
373 c_protocol = gnutls_protocol_get_version (c_session);
374
375 return (scm_from_gnutls_protocol (c_protocol));
376 }
377
378 #undef FUNC_NAME
379
380 SCM_DEFINE (scm_gnutls_session_authentication_type,
381 "session-authentication-type",
382 1, 0, 0,
383 (SCM session),
384 "Return the authentication type (a @code{credential-type} value) "
385 "used by @var{session}.")
386 #define FUNC_NAME s_scm_gnutls_session_authentication_type
387 {
388 gnutls_session_t c_session;
389 gnutls_credentials_type_t c_auth;
390
391 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
392
393 c_auth = gnutls_auth_get_type (c_session);
394
395 return (scm_from_gnutls_credentials (c_auth));
396 }
397
398 #undef FUNC_NAME
399
400 SCM_DEFINE (scm_gnutls_session_server_authentication_type,
401 "session-server-authentication-type",
402 1, 0, 0,
403 (SCM session),
404 "Return the server authentication type (a "
405 "@code{credential-type} value) used in @var{session}.")
406 #define FUNC_NAME s_scm_gnutls_session_server_authentication_type
407 {
408 gnutls_session_t c_session;
409 gnutls_credentials_type_t c_auth;
410
411 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
412
413 c_auth = gnutls_auth_server_get_type (c_session);
414
415 return (scm_from_gnutls_credentials (c_auth));
416 }
417
418 #undef FUNC_NAME
419
420 SCM_DEFINE (scm_gnutls_session_client_authentication_type,
421 "session-client-authentication-type",
422 1, 0, 0,
423 (SCM session),
424 "Return the client authentication type (a "
425 "@code{credential-type} value) used in @var{session}.")
426 #define FUNC_NAME s_scm_gnutls_session_client_authentication_type
427 {
428 gnutls_session_t c_session;
429 gnutls_credentials_type_t c_auth;
430
431 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
432
433 c_auth = gnutls_auth_client_get_type (c_session);
434
435 return (scm_from_gnutls_credentials (c_auth));
436 }
437
438 #undef FUNC_NAME
439
440 SCM_DEFINE (scm_gnutls_session_peer_certificate_chain,
441 "session-peer-certificate-chain",
442 1, 0, 0,
443 (SCM session),
444 "Return the a list of certificates in raw format (u8vectors) "
445 "where the first one is the peer's certificate. In the case "
446 "of OpenPGP, there is always exactly one certificate. In the "
447 "case of X.509, subsequent certificates indicate form a "
448 "certificate chain. Return the empty list if no certificate "
449 "was sent.")
450 #define FUNC_NAME s_scm_gnutls_session_peer_certificate_chain
451 {
452 SCM result;
453 gnutls_session_t c_session;
454 const gnutls_datum_t *c_cert;
455 unsigned int c_list_size;
456
457 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
458
459 c_cert = gnutls_certificate_get_peers (c_session, &c_list_size);
460
461 if (EXPECT_FALSE (c_cert == NULL))
462 result = SCM_EOL;
463 else
464 {
465 SCM pair;
466 unsigned int i;
467
468 result = scm_make_list (scm_from_uint (c_list_size), SCM_UNSPECIFIED);
469
470 for (i = 0, pair = result; i < c_list_size; i++, pair = SCM_CDR (pair))
471 {
472 unsigned char *c_cert_copy;
473
474 c_cert_copy = (unsigned char *) malloc (c_cert[i].size);
475 if (EXPECT_FALSE (c_cert_copy == NULL))
476 scm_gnutls_error (GNUTLS_E_MEMORY_ERROR, FUNC_NAME);
477
478 memcpy (c_cert_copy, c_cert[i].data, c_cert[i].size);
479
480 SCM_SETCAR (pair, scm_take_u8vector (c_cert_copy, c_cert[i].size));
481 }
482 }
483
484 return result;
485 }
486
487 #undef FUNC_NAME
488
489 SCM_DEFINE (scm_gnutls_session_our_certificate_chain,
490 "session-our-certificate-chain",
491 1, 0, 0,
492 (SCM session),
493 "Return our certificate chain for @var{session} (as sent to "
494 "the peer) in raw format (a u8vector). In the case of OpenPGP "
495 "there is exactly one certificate. Return the empty list "
496 "if no certificate was used.")
497 #define FUNC_NAME s_scm_gnutls_session_our_certificate_chain
498 {
499 SCM result;
500 gnutls_session_t c_session;
501 const gnutls_datum_t *c_cert;
502 unsigned char *c_cert_copy;
503
504 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
505
506 /* XXX: Currently, the C function actually returns only one certificate.
507 Future versions of the API may provide the full certificate chain, as
508 for `gnutls_certificate_get_peers ()'. */
509 c_cert = gnutls_certificate_get_ours (c_session);
510
511 if (EXPECT_FALSE (c_cert == NULL))
512 result = SCM_EOL;
513 else
514 {
515 c_cert_copy = (unsigned char *) malloc (c_cert->size);
516 if (EXPECT_FALSE (c_cert_copy == NULL))
517 scm_gnutls_error (GNUTLS_E_MEMORY_ERROR, FUNC_NAME);
518
519 memcpy (c_cert_copy, c_cert->data, c_cert->size);
520
521 result = scm_list_1 (scm_take_u8vector (c_cert_copy, c_cert->size));
522 }
523
524 return result;
525 }
526
527 #undef FUNC_NAME
528
529 SCM_DEFINE (scm_gnutls_set_server_session_certificate_request_x,
530 "set-server-session-certificate-request!",
531 2, 0, 0,
532 (SCM session, SCM request),
533 "Tell how @var{session}, a server-side session, should deal "
534 "with certificate requests. @var{request} should be either "
535 "@code{certificate-request/request} or "
536 "@code{certificate-request/require}.")
537 #define FUNC_NAME s_scm_gnutls_set_server_session_certificate_request_x
538 {
539 gnutls_session_t c_session;
540 gnutls_certificate_status_t c_request;
541
542 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
543 c_request = scm_to_gnutls_certificate_request (request, 2, FUNC_NAME);
544
545 gnutls_certificate_server_set_request (c_session, c_request);
546
547 return SCM_UNSPECIFIED;
548 }
549
550 #undef FUNC_NAME
551
552
553 /* Choice of a protocol and cipher suite. */
554
555 SCM_DEFINE (scm_gnutls_set_default_priority_x,
556 "set-session-default-priority!", 1, 0, 0,
557 (SCM session), "Have @var{session} use the default priorities.")
558 #define FUNC_NAME s_scm_gnutls_set_default_priority_x
559 {
560 gnutls_session_t c_session;
561
562 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
563 gnutls_set_default_priority (c_session);
564
565 return SCM_UNSPECIFIED;
566 }
567
568 #undef FUNC_NAME
569
570 SCM_DEFINE (scm_gnutls_set_session_priorities_x,
571 "set-session-priorities!", 2, 0, 0,
572 (SCM session, SCM priorities),
573 "Have @var{session} use the given @var{priorities} for "
574 "the ciphers, key exchange methods, MACs and compression "
575 "methods. @var{priorities} must be a string (@pxref{"
576 "Priority Strings,,, gnutls, GnuTLS@comma{} Transport Layer "
577 "Security Library for the GNU system}). When @var{priorities} "
578 "cannot be parsed, an @code{error/invalid-request} error "
579 "is raised, with an extra argument indication the position "
580 "of the error.\n")
581 #define FUNC_NAME s_scm_gnutls_set_session_priorities_x
582 {
583 int err;
584 char *c_priorities;
585 const char *err_pos;
586 gnutls_session_t c_session;
587 size_t pos;
588
589 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
590 c_priorities = scm_to_locale_string (priorities); /* XXX: to_latin1_string */
591
592 err = gnutls_priority_set_direct (c_session, c_priorities, &err_pos);
593 if (err == GNUTLS_E_INVALID_REQUEST)
594 pos = err_pos - c_priorities;
595
596 free (c_priorities);
597
598 switch (err)
599 {
600 case GNUTLS_E_SUCCESS:
601 break;
602 case GNUTLS_E_INVALID_REQUEST:
603 {
604 scm_gnutls_error_with_args (err, FUNC_NAME,
605 scm_list_1 (scm_from_size_t (pos)));
606 break;
607 }
608 default:
609 scm_gnutls_error (err, FUNC_NAME);
610 }
611
612 return SCM_UNSPECIFIED;
613 }
614 #undef FUNC_NAME
615
616 SCM_DEFINE (scm_gnutls_cipher_suite_to_string, "cipher-suite->string",
617 3, 0, 0,
618 (SCM kx, SCM cipher, SCM mac),
619 "Return the name of the given cipher suite.")
620 #define FUNC_NAME s_scm_gnutls_cipher_suite_to_string
621 {
622 gnutls_kx_algorithm_t c_kx;
623 gnutls_cipher_algorithm_t c_cipher;
624 gnutls_mac_algorithm_t c_mac;
625 const char *c_name;
626
627 c_kx = scm_to_gnutls_kx (kx, 1, FUNC_NAME);
628 c_cipher = scm_to_gnutls_cipher (cipher, 2, FUNC_NAME);
629 c_mac = scm_to_gnutls_mac (mac, 3, FUNC_NAME);
630
631 c_name = gnutls_cipher_suite_get_name (c_kx, c_cipher, c_mac);
632
633 return (scm_from_locale_string (c_name));
634 }
635
636 #undef FUNC_NAME
637
638 SCM_DEFINE (scm_gnutls_set_session_credentials_x, "set-session-credentials!",
639 2, 0, 0,
640 (SCM session, SCM cred),
641 "Use @var{cred} as @var{session}'s credentials.")
642 #define FUNC_NAME s_scm_gnutls_set_session_credentials_x
643 {
644 int err = 0;
645 gnutls_session_t c_session;
646
647 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
648
649 if (SCM_SMOB_PREDICATE (scm_tc16_gnutls_certificate_credentials, cred))
650 {
651 gnutls_certificate_credentials_t c_cred;
652
653 c_cred = scm_to_gnutls_certificate_credentials (cred, 2, FUNC_NAME);
654 err =
655 gnutls_credentials_set (c_session, GNUTLS_CRD_CERTIFICATE, c_cred);
656 }
657 else
658 if (SCM_SMOB_PREDICATE
659 (scm_tc16_gnutls_anonymous_client_credentials, cred))
660 {
661 gnutls_anon_client_credentials_t c_cred;
662
663 c_cred = scm_to_gnutls_anonymous_client_credentials (cred, 2,
664 FUNC_NAME);
665 err = gnutls_credentials_set (c_session, GNUTLS_CRD_ANON, c_cred);
666 }
667 else if (SCM_SMOB_PREDICATE (scm_tc16_gnutls_anonymous_server_credentials,
668 cred))
669 {
670 gnutls_anon_server_credentials_t c_cred;
671
672 c_cred = scm_to_gnutls_anonymous_server_credentials (cred, 2,
673 FUNC_NAME);
674 err = gnutls_credentials_set (c_session, GNUTLS_CRD_ANON, c_cred);
675 }
676 #ifdef ENABLE_SRP
677 else if (SCM_SMOB_PREDICATE (scm_tc16_gnutls_srp_client_credentials, cred))
678 {
679 gnutls_srp_client_credentials_t c_cred;
680
681 c_cred = scm_to_gnutls_srp_client_credentials (cred, 2, FUNC_NAME);
682 err = gnutls_credentials_set (c_session, GNUTLS_CRD_SRP, c_cred);
683 }
684 else if (SCM_SMOB_PREDICATE (scm_tc16_gnutls_srp_server_credentials, cred))
685 {
686 gnutls_srp_server_credentials_t c_cred;
687
688 c_cred = scm_to_gnutls_srp_server_credentials (cred, 2, FUNC_NAME);
689 err = gnutls_credentials_set (c_session, GNUTLS_CRD_SRP, c_cred);
690 }
691 #endif
692 else if (SCM_SMOB_PREDICATE (scm_tc16_gnutls_psk_client_credentials, cred))
693 {
694 gnutls_psk_client_credentials_t c_cred;
695
696 c_cred = scm_to_gnutls_psk_client_credentials (cred, 2, FUNC_NAME);
697 err = gnutls_credentials_set (c_session, GNUTLS_CRD_PSK, c_cred);
698 }
699 else if (SCM_SMOB_PREDICATE (scm_tc16_gnutls_psk_server_credentials, cred))
700 {
701 gnutls_psk_server_credentials_t c_cred;
702
703 c_cred = scm_to_gnutls_psk_server_credentials (cred, 2, FUNC_NAME);
704 err = gnutls_credentials_set (c_session, GNUTLS_CRD_PSK, c_cred);
705 }
706 else
707 scm_wrong_type_arg (FUNC_NAME, 2, cred);
708
709 if (EXPECT_FALSE (err))
710 scm_gnutls_error (err, FUNC_NAME);
711 else
712 register_weak_reference (session, cred);
713
714 return SCM_UNSPECIFIED;
715 }
716
717 #undef FUNC_NAME
718
719 SCM_DEFINE (scm_gnutls_set_session_server_name_x, "set-session-server-name!",
720 3, 0, 0,
721 (SCM session, SCM type, SCM name),
722 "For a client, this procedure provides a way to inform "
723 "the server that it is known under @var{name}, @i{via} the "
724 "@code{SERVER NAME} TLS extension. @var{type} must be "
725 "a @code{server-name-type} value, @var{server-name-type/dns} "
726 "for DNS names.")
727 #define FUNC_NAME s_scm_gnutls_set_session_server_name_x
728 {
729 int err;
730 gnutls_session_t c_session;
731 gnutls_server_name_type_t c_type;
732 char *c_name;
733
734 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
735 c_type = scm_to_gnutls_server_name_type (type, 2, FUNC_NAME);
736 SCM_VALIDATE_STRING (3, name);
737
738 c_name = scm_to_locale_string (name);
739
740 err = gnutls_server_name_set (c_session, c_type, c_name,
741 strlen (c_name));
742 free (c_name);
743
744 if (EXPECT_FALSE (err != GNUTLS_E_SUCCESS))
745 scm_gnutls_error (err, FUNC_NAME);
746
747 return SCM_UNSPECIFIED;
748 }
749 #undef FUNC_NAME
750
751
752 /* Record layer. */
753
754 SCM_DEFINE (scm_gnutls_record_send, "record-send", 2, 0, 0,
755 (SCM session, SCM array),
756 "Send the record constituted by @var{array} through "
757 "@var{session}.")
758 #define FUNC_NAME s_scm_gnutls_record_send
759 {
760 SCM result;
761 ssize_t c_result;
762 gnutls_session_t c_session;
763 scm_t_array_handle c_handle;
764 const char *c_array;
765 size_t c_len;
766
767 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
768 SCM_VALIDATE_ARRAY (2, array);
769
770 c_array = scm_gnutls_get_array (array, &c_handle, &c_len, FUNC_NAME);
771
772 c_result = gnutls_record_send (c_session, c_array, c_len);
773
774 scm_gnutls_release_array (&c_handle);
775
776 if (EXPECT_TRUE (c_result >= 0))
777 result = scm_from_ssize_t (c_result);
778 else
779 scm_gnutls_error (c_result, FUNC_NAME);
780
781 return (result);
782 }
783
784 #undef FUNC_NAME
785
786 SCM_DEFINE (scm_gnutls_record_receive_x, "record-receive!", 2, 0, 0,
787 (SCM session, SCM array),
788 "Receive data from @var{session} into @var{array}, a uniform "
789 "homogeneous array. Return the number of bytes actually "
790 "received.")
791 #define FUNC_NAME s_scm_gnutls_record_receive_x
792 {
793 SCM result;
794 ssize_t c_result;
795 gnutls_session_t c_session;
796 scm_t_array_handle c_handle;
797 char *c_array;
798 size_t c_len;
799
800 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
801 SCM_VALIDATE_ARRAY (2, array);
802
803 c_array = scm_gnutls_get_writable_array (array, &c_handle, &c_len,
804 FUNC_NAME);
805
806 c_result = gnutls_record_recv (c_session, c_array, c_len);
807
808 scm_gnutls_release_array (&c_handle);
809
810 if (EXPECT_TRUE (c_result >= 0))
811 result = scm_from_ssize_t (c_result);
812 else
813 scm_gnutls_error (c_result, FUNC_NAME);
814
815 return (result);
816 }
817
818 #undef FUNC_NAME
819
820
821 /* Whether we're using Guile < 2.2. */
822 #define USING_GUILE_BEFORE_2_2 \
823 (SCM_MAJOR_VERSION < 2 \
824 || (SCM_MAJOR_VERSION == 2 && SCM_MINOR_VERSION == 0))
825
826 /* The session record port type. Guile 2.1.4 introduced a brand new port API,
827 so we have a separate implementation for these newer versions. */
828 #if USING_GUILE_BEFORE_2_2
829 static scm_t_bits session_record_port_type;
830
831 /* Hint for the `scm_gc_' functions. */
832 static const char session_record_port_gc_hint[] =
833 "gnutls-session-record-port";
834 #else
835 static scm_t_port_type *session_record_port_type;
836 #endif
837
838 /* Return the session associated with PORT. */
839 #define SCM_GNUTLS_SESSION_RECORD_PORT_SESSION(_port) \
840 (SCM_PACK (SCM_STREAM (_port)))
841
842 /* Size of a session port's input buffer. */
843 #define SCM_GNUTLS_SESSION_RECORD_PORT_BUFFER_SIZE 4096
844
845
846 #if SCM_MAJOR_VERSION == 1 && SCM_MINOR_VERSION <= 8
847
848 /* Mark the session associated with PORT. */
849 static SCM
mark_session_record_port(SCM port)850 mark_session_record_port (SCM port)
851 {
852 return (SCM_GNUTLS_SESSION_RECORD_PORT_SESSION (port));
853 }
854
855 static size_t
free_session_record_port(SCM port)856 free_session_record_port (SCM port)
857 #define FUNC_NAME "free_session_record_port"
858 {
859 SCM session;
860 scm_t_port *c_port;
861
862 session = SCM_GNUTLS_SESSION_RECORD_PORT_SESSION (port);
863
864 /* SESSION _can_ be invalid at this point: it can be freed in the same GC
865 cycle as PORT, just before PORT. Thus, we need to check whether SESSION
866 still points to a session SMOB. */
867 if (SCM_SMOB_PREDICATE (scm_tc16_gnutls_session, session))
868 {
869 /* SESSION is still valid. Disassociate PORT from SESSION. */
870 gnutls_session_t c_session;
871
872 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
873 SCM_GNUTLS_SET_SESSION_RECORD_PORT (c_session, SCM_BOOL_F);
874 }
875
876 /* Free the input buffer of PORT. */
877 c_port = SCM_PTAB_ENTRY (port);
878 scm_gc_free (c_port->read_buf, c_port->read_buf_size,
879 session_record_port_gc_hint);
880
881 return 0;
882 }
883
884 #undef FUNC_NAME
885
886 #endif /* SCM_MAJOR_VERSION == 1 && SCM_MINOR_VERSION <= 8 */
887
888
889 #if USING_GUILE_BEFORE_2_2
890
891 /* Data passed to `do_fill_port ()'. */
892 typedef struct
893 {
894 scm_t_port *c_port;
895 gnutls_session_t c_session;
896 } fill_port_data_t;
897
898 /* Actually fill a session record port (see below). */
899 static void *
do_fill_port(void * data)900 do_fill_port (void *data)
901 {
902 int chr;
903 ssize_t result;
904 scm_t_port *c_port;
905 const fill_port_data_t *args = (fill_port_data_t *) data;
906
907 c_port = args->c_port;
908
909 /* We can get GNUTLS_E_AGAIN due to a "short read", which does _not_
910 correspond to an actual EAGAIN from read(2) since the underlying file
911 descriptor is blocking. Thus, we can safely loop right away. */
912 do
913 result = gnutls_record_recv (args->c_session,
914 c_port->read_buf, c_port->read_buf_size);
915 while (result == GNUTLS_E_AGAIN || result == GNUTLS_E_INTERRUPTED);
916
917 if (EXPECT_TRUE (result > 0))
918 {
919 c_port->read_pos = c_port->read_buf;
920 c_port->read_end = c_port->read_buf + result;
921 chr = (int) *c_port->read_buf;
922 }
923 else if (result == 0)
924 chr = EOF;
925 else
926 scm_gnutls_error (result, "fill_session_record_port_input");
927
928 return ((void *) (uintptr_t) chr);
929 }
930
931 /* Fill in the input buffer of PORT. */
932 static int
fill_session_record_port_input(SCM port)933 fill_session_record_port_input (SCM port)
934 #define FUNC_NAME "fill_session_record_port_input"
935 {
936 int chr;
937 scm_t_port *c_port = SCM_PTAB_ENTRY (port);
938
939 if (c_port->read_pos >= c_port->read_end)
940 {
941 SCM session;
942 fill_port_data_t c_args;
943 gnutls_session_t c_session;
944
945 session = SCM_GNUTLS_SESSION_RECORD_PORT_SESSION (port);
946 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
947
948 c_args.c_session = c_session;
949 c_args.c_port = c_port;
950
951 if (SCM_GNUTLS_SESSION_TRANSPORT_IS_FD (c_session))
952 /* SESSION's underlying transport is a raw file descriptor, so we
953 must leave "Guile mode" to allow the GC to run. */
954 chr = (intptr_t) scm_without_guile (do_fill_port, &c_args);
955 else
956 /* SESSION's underlying transport is a port, so don't leave "Guile
957 mode". */
958 chr = (intptr_t) do_fill_port (&c_args);
959 }
960 else
961 chr = (int) *c_port->read_pos;
962
963 return chr;
964 }
965
966 #undef FUNC_NAME
967
968 /* Write SIZE octets from DATA to PORT. */
969 static void
write_to_session_record_port(SCM port,const void * data,size_t size)970 write_to_session_record_port (SCM port, const void *data, size_t size)
971 #define FUNC_NAME "write_to_session_record_port"
972 {
973 SCM session;
974 gnutls_session_t c_session;
975 ssize_t c_result;
976 size_t c_sent = 0;
977
978 session = SCM_GNUTLS_SESSION_RECORD_PORT_SESSION (port);
979 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
980
981 while (c_sent < size)
982 {
983 c_result = gnutls_record_send (c_session, (char *) data + c_sent,
984 size - c_sent);
985 if (EXPECT_FALSE (c_result < 0))
986 scm_gnutls_error (c_result, FUNC_NAME);
987 else
988 c_sent += c_result;
989 }
990 }
991
992 #undef FUNC_NAME
993
994 /* Return a new session port for SESSION. */
995 static SCM
make_session_record_port(SCM session)996 make_session_record_port (SCM session)
997 {
998 SCM port;
999 scm_t_port *c_port;
1000 unsigned char *c_port_buf;
1001 const unsigned long mode_bits = SCM_OPN | SCM_RDNG | SCM_WRTNG;
1002
1003 c_port_buf = (unsigned char *)
1004 scm_gc_malloc_pointerless (SCM_GNUTLS_SESSION_RECORD_PORT_BUFFER_SIZE,
1005 session_record_port_gc_hint);
1006
1007 /* Create a new port. */
1008 port = scm_new_port_table_entry (session_record_port_type);
1009 c_port = SCM_PTAB_ENTRY (port);
1010
1011 /* Mark PORT as open, readable and writable (hmm, how elegant...). */
1012 SCM_SET_CELL_TYPE (port, session_record_port_type | mode_bits);
1013
1014 /* Associate it with SESSION. */
1015 SCM_SETSTREAM (port, SCM_UNPACK (session));
1016
1017 c_port->read_pos = c_port->read_end = c_port->read_buf = c_port_buf;
1018 c_port->read_buf_size = SCM_GNUTLS_SESSION_RECORD_PORT_BUFFER_SIZE;
1019
1020 c_port->write_buf = c_port->write_pos = &c_port->shortbuf;
1021 c_port->write_buf_size = 1;
1022
1023 return (port);
1024 }
1025
1026 #else /* !USING_GUILE_BEFORE_2_2 */
1027
1028 static size_t
read_from_session_record_port(SCM port,SCM dst,size_t start,size_t count)1029 read_from_session_record_port (SCM port, SCM dst, size_t start, size_t count)
1030 #define FUNC_NAME "read_from_session_record_port"
1031 {
1032 SCM session;
1033 gnutls_session_t c_session;
1034 char *read_buf;
1035 ssize_t result;
1036
1037 session = SCM_GNUTLS_SESSION_RECORD_PORT_SESSION (port);
1038 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
1039
1040 read_buf = (char *) SCM_BYTEVECTOR_CONTENTS (dst) + start;
1041
1042 /* We can get GNUTLS_E_AGAIN due to a "short read", which does _not_
1043 correspond to an actual EAGAIN from read(2) if the underlying file
1044 descriptor is blocking--e.g., from 'get_last_packet', returning
1045 GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE.
1046
1047 If SESSION is backed by a file descriptor, return -1 to indicate that
1048 we'd better poll; otherwise loop, which is good enough if the underlying
1049 port is blocking. */
1050 do
1051 result = gnutls_record_recv (c_session, read_buf, count);
1052 while (result == GNUTLS_E_INTERRUPTED
1053 || (result == GNUTLS_E_AGAIN
1054 && !SCM_GNUTLS_SESSION_TRANSPORT_IS_FD (c_session)));
1055
1056 if (result == GNUTLS_E_AGAIN
1057 && SCM_GNUTLS_SESSION_TRANSPORT_IS_FD (c_session))
1058 /* Tell Guile that reading would block. */
1059 return (size_t) -1;
1060
1061 if (EXPECT_FALSE (result < 0))
1062 /* FIXME: Silently swallowed! */
1063 scm_gnutls_error (result, FUNC_NAME);
1064
1065 return result;
1066 }
1067 #undef FUNC_NAME
1068
1069 /* Return the file descriptor that backs PORT. This function is called upon a
1070 blocking read--i.e., 'read_from_session_record_port' returned -1. */
1071 static int
session_record_port_fd(SCM port)1072 session_record_port_fd (SCM port)
1073 {
1074 SCM session;
1075 gnutls_session_t c_session;
1076
1077 session = SCM_GNUTLS_SESSION_RECORD_PORT_SESSION (port);
1078 c_session = scm_to_gnutls_session (session, 1, __func__);
1079
1080 assert (SCM_GNUTLS_SESSION_TRANSPORT_IS_FD (c_session));
1081
1082 return gnutls_transport_get_int (c_session);
1083 }
1084
1085 static size_t
write_to_session_record_port(SCM port,SCM src,size_t start,size_t count)1086 write_to_session_record_port (SCM port, SCM src, size_t start, size_t count)
1087 #define FUNC_NAME "write_to_session_record_port"
1088 {
1089 SCM session;
1090 gnutls_session_t c_session;
1091 char *data;
1092 ssize_t result;
1093
1094 session = SCM_GNUTLS_SESSION_RECORD_PORT_SESSION (port);
1095 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
1096 data = (char *) SCM_BYTEVECTOR_CONTENTS (src) + start;
1097
1098 result = gnutls_record_send (c_session, data, count);
1099
1100 if (EXPECT_FALSE (result < 0))
1101 scm_gnutls_error (result, FUNC_NAME);
1102
1103 return result;
1104 }
1105 #undef FUNC_NAME
1106
1107 /* Return a new session port for SESSION. */
1108 static SCM
make_session_record_port(SCM session)1109 make_session_record_port (SCM session)
1110 {
1111 return scm_c_make_port (session_record_port_type,
1112 SCM_OPN | SCM_RDNG | SCM_WRTNG | SCM_BUF0,
1113 SCM_UNPACK (session));
1114 }
1115
1116 #endif /* !USING_GUILE_BEFORE_2_2 */
1117
1118
1119 SCM_DEFINE (scm_gnutls_session_record_port, "session-record-port", 1, 0, 0,
1120 (SCM session),
1121 "Return a read-write port that may be used to communicate over "
1122 "@var{session}. All invocations of @code{session-port} on a "
1123 "given session return the same object (in the sense of "
1124 "@code{eq?}).")
1125 #define FUNC_NAME s_scm_gnutls_session_record_port
1126 {
1127 SCM port;
1128 gnutls_session_t c_session;
1129
1130 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
1131 port = SCM_GNUTLS_SESSION_RECORD_PORT (c_session);
1132
1133 if (!SCM_PORTP (port))
1134 {
1135 /* Lazily create a new session port. */
1136 port = make_session_record_port (session);
1137 SCM_GNUTLS_SET_SESSION_RECORD_PORT (c_session, port);
1138 }
1139
1140 return (port);
1141 }
1142
1143 #undef FUNC_NAME
1144
1145 /* Create the session port type. */
1146 static void
scm_init_gnutls_session_record_port_type(void)1147 scm_init_gnutls_session_record_port_type (void)
1148 {
1149 session_record_port_type =
1150 scm_make_port_type ("gnutls-session-port",
1151 #if USING_GUILE_BEFORE_2_2
1152 fill_session_record_port_input,
1153 #else
1154 read_from_session_record_port,
1155 #endif
1156 write_to_session_record_port);
1157
1158 #if !USING_GUILE_BEFORE_2_2
1159 scm_set_port_read_wait_fd (session_record_port_type,
1160 session_record_port_fd);
1161 #endif
1162
1163 /* Guile >= 1.9.3 doesn't need a custom mark procedure, and doesn't need a
1164 finalizer (since memory associated with the port is automatically
1165 reclaimed.) */
1166 #if SCM_MAJOR_VERSION == 1 && SCM_MINOR_VERSION <= 8
1167 scm_set_port_mark (session_record_port_type, mark_session_record_port);
1168 scm_set_port_free (session_record_port_type, free_session_record_port);
1169 #endif
1170 }
1171
1172
1173 /* Transport. */
1174
1175 SCM_DEFINE (scm_gnutls_set_session_transport_fd_x,
1176 "set-session-transport-fd!", 2, 0, 0, (SCM session, SCM fd),
1177 "Use file descriptor @var{fd} as the underlying transport for "
1178 "@var{session}.")
1179 #define FUNC_NAME s_scm_gnutls_set_session_transport_fd_x
1180 {
1181 gnutls_session_t c_session;
1182 int c_fd;
1183
1184 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
1185 c_fd = (int) scm_to_uint (fd);
1186
1187 gnutls_transport_set_ptr (c_session,
1188 (gnutls_transport_ptr_t) (intptr_t) c_fd);
1189
1190 SCM_GNUTLS_SET_SESSION_TRANSPORT_IS_FD (c_session, 1);
1191
1192 return SCM_UNSPECIFIED;
1193 }
1194
1195 #undef FUNC_NAME
1196
1197 /* Pull SIZE octets from TRANSPORT (a Scheme port) into DATA. */
1198 static ssize_t
pull_from_port(gnutls_transport_ptr_t transport,void * data,size_t size)1199 pull_from_port (gnutls_transport_ptr_t transport, void *data, size_t size)
1200 {
1201 SCM port;
1202 ssize_t result;
1203
1204 port = SCM_PACK ((scm_t_bits) transport);
1205
1206 result = scm_c_read (port, data, size);
1207
1208 return ((ssize_t) result);
1209 }
1210
1211 /* Write SIZE octets from DATA to TRANSPORT (a Scheme port). */
1212 static ssize_t
push_to_port(gnutls_transport_ptr_t transport,const void * data,size_t size)1213 push_to_port (gnutls_transport_ptr_t transport, const void *data, size_t size)
1214 {
1215 SCM port;
1216
1217 port = SCM_PACK ((scm_t_bits) transport);
1218
1219 scm_c_write (port, data, size);
1220
1221 /* All we can do is assume that all SIZE octets were written. */
1222 return (size);
1223 }
1224
1225 SCM_DEFINE (scm_gnutls_set_session_transport_port_x,
1226 "set-session-transport-port!",
1227 2, 0, 0,
1228 (SCM session, SCM port),
1229 "Use @var{port} as the input/output port for @var{session}.")
1230 #define FUNC_NAME s_scm_gnutls_set_session_transport_port_x
1231 {
1232 gnutls_session_t c_session;
1233
1234 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
1235 SCM_VALIDATE_PORT (2, port);
1236
1237 /* Note: We do not attempt to optimize the case where PORT is a file port
1238 (i.e., over a file descriptor), because of port buffering issues. Users
1239 are expected to explicitly use `set-session-transport-fd!' and `fileno'
1240 when they wish to do it. */
1241
1242 gnutls_transport_set_ptr (c_session,
1243 (gnutls_transport_ptr_t) SCM_UNPACK (port));
1244 gnutls_transport_set_push_function (c_session, push_to_port);
1245 gnutls_transport_set_pull_function (c_session, pull_from_port);
1246
1247 SCM_GNUTLS_SET_SESSION_TRANSPORT_IS_FD (c_session, 0);
1248
1249 return SCM_UNSPECIFIED;
1250 }
1251
1252 #undef FUNC_NAME
1253
1254
1255 /* Diffie-Hellman. */
1256
1257 typedef int (*pkcs_export_function_t) (void *, gnutls_x509_crt_fmt_t,
1258 unsigned char *, size_t *);
1259
1260 /* Hint for the `scm_gc' functions. */
1261 static const char pkcs_export_gc_hint[] = "gnutls-pkcs-export";
1262
1263
1264 /* Export DH/RSA parameters PARAMS through EXPORT, using format FORMAT.
1265 Return a `u8vector'. */
1266 static inline SCM
pkcs_export_parameters(pkcs_export_function_t export,void * params,gnutls_x509_crt_fmt_t format,const char * func_name)1267 pkcs_export_parameters (pkcs_export_function_t export,
1268 void *params, gnutls_x509_crt_fmt_t format,
1269 const char *func_name)
1270 #define FUNC_NAME func_name
1271 {
1272 int err;
1273 unsigned char *output;
1274 size_t output_len, output_total_len = 4096;
1275
1276 output = (unsigned char *) scm_gc_malloc (output_total_len,
1277 pkcs_export_gc_hint);
1278 do
1279 {
1280 output_len = output_total_len;
1281 err = export (params, format, output, &output_len);
1282
1283 if (err == GNUTLS_E_SHORT_MEMORY_BUFFER)
1284 {
1285 output = scm_gc_realloc (output, output_total_len,
1286 output_total_len * 2, pkcs_export_gc_hint);
1287 output_total_len *= 2;
1288 }
1289 }
1290 while (err == GNUTLS_E_SHORT_MEMORY_BUFFER);
1291
1292 if (EXPECT_FALSE (err))
1293 {
1294 scm_gc_free (output, output_total_len, pkcs_export_gc_hint);
1295 scm_gnutls_error (err, FUNC_NAME);
1296 }
1297
1298 if (output_len != output_total_len)
1299 /* Shrink the output buffer. */
1300 output = scm_gc_realloc (output, output_total_len,
1301 output_len, pkcs_export_gc_hint);
1302
1303 return (scm_take_u8vector (output, output_len));
1304 }
1305
1306 #undef FUNC_NAME
1307
1308
1309 SCM_DEFINE (scm_gnutls_make_dh_parameters, "make-dh-parameters", 1, 0, 0,
1310 (SCM bits), "Return new Diffie-Hellman parameters.")
1311 #define FUNC_NAME s_scm_gnutls_make_dh_parameters
1312 {
1313 int err;
1314 unsigned c_bits;
1315 gnutls_dh_params_t c_dh_params;
1316
1317 c_bits = scm_to_uint (bits);
1318
1319 err = gnutls_dh_params_init (&c_dh_params);
1320 if (EXPECT_FALSE (err))
1321 scm_gnutls_error (err, FUNC_NAME);
1322
1323 err = gnutls_dh_params_generate2 (c_dh_params, c_bits);
1324 if (EXPECT_FALSE (err))
1325 {
1326 gnutls_dh_params_deinit (c_dh_params);
1327 scm_gnutls_error (err, FUNC_NAME);
1328 }
1329
1330 return (scm_from_gnutls_dh_parameters (c_dh_params));
1331 }
1332
1333 #undef FUNC_NAME
1334
1335 SCM_DEFINE (scm_gnutls_pkcs3_import_dh_parameters,
1336 "pkcs3-import-dh-parameters",
1337 2, 0, 0,
1338 (SCM array, SCM format),
1339 "Import Diffie-Hellman parameters in PKCS3 format (further "
1340 "specified by @var{format}, an @code{x509-certificate-format} "
1341 "value) from @var{array} (a homogeneous array) and return a "
1342 "new @code{dh-params} object.")
1343 #define FUNC_NAME s_scm_gnutls_pkcs3_import_dh_parameters
1344 {
1345 int err;
1346 gnutls_x509_crt_fmt_t c_format;
1347 gnutls_dh_params_t c_dh_params;
1348 scm_t_array_handle c_handle;
1349 const char *c_array;
1350 size_t c_len;
1351 gnutls_datum_t c_datum;
1352
1353 c_format = scm_to_gnutls_x509_certificate_format (format, 2, FUNC_NAME);
1354
1355 c_array = scm_gnutls_get_array (array, &c_handle, &c_len, FUNC_NAME);
1356 c_datum.data = (unsigned char *) c_array;
1357 c_datum.size = c_len;
1358
1359 err = gnutls_dh_params_init (&c_dh_params);
1360 if (EXPECT_FALSE (err))
1361 {
1362 scm_gnutls_release_array (&c_handle);
1363 scm_gnutls_error (err, FUNC_NAME);
1364 }
1365
1366 err = gnutls_dh_params_import_pkcs3 (c_dh_params, &c_datum, c_format);
1367 scm_gnutls_release_array (&c_handle);
1368
1369 if (EXPECT_FALSE (err))
1370 {
1371 gnutls_dh_params_deinit (c_dh_params);
1372 scm_gnutls_error (err, FUNC_NAME);
1373 }
1374
1375 return (scm_from_gnutls_dh_parameters (c_dh_params));
1376 }
1377
1378 #undef FUNC_NAME
1379
1380 SCM_DEFINE (scm_gnutls_pkcs3_export_dh_parameters,
1381 "pkcs3-export-dh-parameters",
1382 2, 0, 0,
1383 (SCM dh_params, SCM format),
1384 "Export Diffie-Hellman parameters @var{dh_params} in PKCS3 "
1385 "format according for @var{format} (an "
1386 "@code{x509-certificate-format} value). Return a "
1387 "@code{u8vector} containing the result.")
1388 #define FUNC_NAME s_scm_gnutls_pkcs3_export_dh_parameters
1389 {
1390 SCM result;
1391 gnutls_dh_params_t c_dh_params;
1392 gnutls_x509_crt_fmt_t c_format;
1393
1394 c_dh_params = scm_to_gnutls_dh_parameters (dh_params, 1, FUNC_NAME);
1395 c_format = scm_to_gnutls_x509_certificate_format (format, 2, FUNC_NAME);
1396
1397 result = pkcs_export_parameters ((pkcs_export_function_t)
1398 gnutls_dh_params_export_pkcs3,
1399 (void *) c_dh_params, c_format, FUNC_NAME);
1400
1401 return (result);
1402 }
1403
1404 #undef FUNC_NAME
1405
1406 SCM_DEFINE (scm_gnutls_set_session_dh_prime_bits_x,
1407 "set-session-dh-prime-bits!", 2, 0, 0,
1408 (SCM session, SCM bits),
1409 "Use @var{bits} DH prime bits for @var{session}.")
1410 #define FUNC_NAME s_scm_gnutls_set_session_dh_prime_bits_x
1411 {
1412 unsigned int c_bits;
1413 gnutls_session_t c_session;
1414
1415 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
1416 c_bits = scm_to_uint (bits);
1417
1418 gnutls_dh_set_prime_bits (c_session, c_bits);
1419
1420 return SCM_UNSPECIFIED;
1421 }
1422
1423 #undef FUNC_NAME
1424
1425
1426 /* Anonymous credentials. */
1427
1428 SCM_DEFINE (scm_gnutls_make_anon_server_credentials,
1429 "make-anonymous-server-credentials",
1430 0, 0, 0, (void), "Return anonymous server credentials.")
1431 #define FUNC_NAME s_scm_gnutls_make_anon_server_credentials
1432 {
1433 int err;
1434 gnutls_anon_server_credentials_t c_cred;
1435
1436 err = gnutls_anon_allocate_server_credentials (&c_cred);
1437
1438 if (EXPECT_FALSE (err))
1439 scm_gnutls_error (err, FUNC_NAME);
1440
1441 return (scm_from_gnutls_anonymous_server_credentials (c_cred));
1442 }
1443
1444 #undef FUNC_NAME
1445
1446 SCM_DEFINE (scm_gnutls_make_anon_client_credentials,
1447 "make-anonymous-client-credentials",
1448 0, 0, 0, (void), "Return anonymous client credentials.")
1449 #define FUNC_NAME s_scm_gnutls_make_anon_client_credentials
1450 {
1451 int err;
1452 gnutls_anon_client_credentials_t c_cred;
1453
1454 err = gnutls_anon_allocate_client_credentials (&c_cred);
1455
1456 if (EXPECT_FALSE (err))
1457 scm_gnutls_error (err, FUNC_NAME);
1458
1459 return (scm_from_gnutls_anonymous_client_credentials (c_cred));
1460 }
1461
1462 #undef FUNC_NAME
1463
1464 SCM_DEFINE (scm_gnutls_set_anonymous_server_dh_parameters_x,
1465 "set-anonymous-server-dh-parameters!", 2, 0, 0,
1466 (SCM cred, SCM dh_params),
1467 "Set the Diffie-Hellman parameters of anonymous server "
1468 "credentials @var{cred}.")
1469 #define FUNC_NAME s_scm_gnutls_set_anonymous_server_dh_parameters_x
1470 {
1471 gnutls_dh_params_t c_dh_params;
1472 gnutls_anon_server_credentials_t c_cred;
1473
1474 c_cred = scm_to_gnutls_anonymous_server_credentials (cred, 1, FUNC_NAME);
1475 c_dh_params = scm_to_gnutls_dh_parameters (dh_params, 2, FUNC_NAME);
1476
1477 gnutls_anon_set_server_dh_params (c_cred, c_dh_params);
1478 register_weak_reference (cred, dh_params);
1479
1480 return SCM_UNSPECIFIED;
1481 }
1482
1483 #undef FUNC_NAME
1484
1485
1486
1487 /* Certificate credentials. */
1488
1489 typedef
1490 int (*certificate_set_file_function_t) (gnutls_certificate_credentials_t,
1491 const char *,
1492 gnutls_x509_crt_fmt_t);
1493
1494 typedef
1495 int (*certificate_set_data_function_t) (gnutls_certificate_credentials_t,
1496 const gnutls_datum_t *,
1497 gnutls_x509_crt_fmt_t);
1498
1499 /* Helper function to implement the `set-file!' functions. */
1500 static unsigned int
set_certificate_file(certificate_set_file_function_t set_file,SCM cred,SCM file,SCM format,const char * func_name)1501 set_certificate_file (certificate_set_file_function_t set_file,
1502 SCM cred, SCM file, SCM format, const char *func_name)
1503 #define FUNC_NAME func_name
1504 {
1505 int err;
1506 char *c_file;
1507 size_t c_file_len;
1508
1509 gnutls_certificate_credentials_t c_cred;
1510 gnutls_x509_crt_fmt_t c_format;
1511
1512 c_cred = scm_to_gnutls_certificate_credentials (cred, 1, FUNC_NAME);
1513 SCM_VALIDATE_STRING (2, file);
1514 c_format = scm_to_gnutls_x509_certificate_format (format, 3, FUNC_NAME);
1515
1516 c_file_len = scm_c_string_length (file);
1517 c_file = FAST_ALLOC (c_file_len + 1);
1518
1519 (void) scm_to_locale_stringbuf (file, c_file, c_file_len + 1);
1520 c_file[c_file_len] = '\0';
1521
1522 err = set_file (c_cred, c_file, c_format);
1523 if (EXPECT_FALSE (err < 0))
1524 scm_gnutls_error (err, FUNC_NAME);
1525
1526 /* Return the number of certificates processed. */
1527 return ((unsigned int) err);
1528 }
1529
1530 #undef FUNC_NAME
1531
1532 /* Helper function implementing the `set-data!' functions. */
1533 static inline unsigned int
set_certificate_data(certificate_set_data_function_t set_data,SCM cred,SCM data,SCM format,const char * func_name)1534 set_certificate_data (certificate_set_data_function_t set_data,
1535 SCM cred, SCM data, SCM format, const char *func_name)
1536 #define FUNC_NAME func_name
1537 {
1538 int err;
1539 gnutls_certificate_credentials_t c_cred;
1540 gnutls_x509_crt_fmt_t c_format;
1541 gnutls_datum_t c_datum;
1542 scm_t_array_handle c_handle;
1543 const char *c_data;
1544 size_t c_len;
1545
1546 c_cred = scm_to_gnutls_certificate_credentials (cred, 1, FUNC_NAME);
1547 SCM_VALIDATE_ARRAY (2, data);
1548 c_format = scm_to_gnutls_x509_certificate_format (format, 3, FUNC_NAME);
1549
1550 c_data = scm_gnutls_get_array (data, &c_handle, &c_len, FUNC_NAME);
1551 c_datum.data = (unsigned char *) c_data;
1552 c_datum.size = c_len;
1553
1554 err = set_data (c_cred, &c_datum, c_format);
1555 scm_gnutls_release_array (&c_handle);
1556
1557 if (EXPECT_FALSE (err < 0))
1558 scm_gnutls_error (err, FUNC_NAME);
1559
1560 /* Return the number of certificates processed. */
1561 return ((unsigned int) err);
1562 }
1563
1564 #undef FUNC_NAME
1565
1566
1567 SCM_DEFINE (scm_gnutls_make_certificate_credentials,
1568 "make-certificate-credentials",
1569 0, 0, 0,
1570 (void),
1571 "Return new certificate credentials (i.e., for use with "
1572 "either X.509 or OpenPGP certificates.")
1573 #define FUNC_NAME s_scm_gnutls_make_certificate_credentials
1574 {
1575 int err;
1576 gnutls_certificate_credentials_t c_cred;
1577
1578 err = gnutls_certificate_allocate_credentials (&c_cred);
1579 if (err)
1580 scm_gnutls_error (err, FUNC_NAME);
1581
1582 return (scm_from_gnutls_certificate_credentials (c_cred));
1583 }
1584
1585 #undef FUNC_NAME
1586
1587 SCM_DEFINE (scm_gnutls_set_certificate_credentials_dh_params_x,
1588 "set-certificate-credentials-dh-parameters!",
1589 2, 0, 0,
1590 (SCM cred, SCM dh_params),
1591 "Use Diffie-Hellman parameters @var{dh_params} for "
1592 "certificate credentials @var{cred}.")
1593 #define FUNC_NAME s_scm_gnutls_set_certificate_credentials_dh_params_x
1594 {
1595 gnutls_dh_params_t c_dh_params;
1596 gnutls_certificate_credentials_t c_cred;
1597
1598 c_cred = scm_to_gnutls_certificate_credentials (cred, 1, FUNC_NAME);
1599 c_dh_params = scm_to_gnutls_dh_parameters (dh_params, 2, FUNC_NAME);
1600
1601 gnutls_certificate_set_dh_params (c_cred, c_dh_params);
1602 register_weak_reference (cred, dh_params);
1603
1604 return SCM_UNSPECIFIED;
1605 }
1606
1607 #undef FUNC_NAME
1608
1609 SCM_DEFINE (scm_gnutls_set_certificate_credentials_x509_key_files_x,
1610 "set-certificate-credentials-x509-key-files!",
1611 4, 0, 0,
1612 (SCM cred, SCM cert_file, SCM key_file, SCM format),
1613 "Use @var{file} as the password file for PSK server "
1614 "credentials @var{cred}.")
1615 #define FUNC_NAME s_scm_gnutls_set_certificate_credentials_x509_key_files_x
1616 {
1617 int err;
1618 gnutls_certificate_credentials_t c_cred;
1619 gnutls_x509_crt_fmt_t c_format;
1620 char *c_cert_file, *c_key_file;
1621 size_t c_cert_file_len, c_key_file_len;
1622
1623 c_cred = scm_to_gnutls_certificate_credentials (cred, 1, FUNC_NAME);
1624 SCM_VALIDATE_STRING (2, cert_file);
1625 SCM_VALIDATE_STRING (3, key_file);
1626 c_format = scm_to_gnutls_x509_certificate_format (format, 2, FUNC_NAME);
1627
1628 c_cert_file_len = scm_c_string_length (cert_file);
1629 c_cert_file = FAST_ALLOC (c_cert_file_len + 1);
1630
1631 c_key_file_len = scm_c_string_length (key_file);
1632 c_key_file = FAST_ALLOC (c_key_file_len + 1);
1633
1634 (void) scm_to_locale_stringbuf (cert_file, c_cert_file,
1635 c_cert_file_len + 1);
1636 c_cert_file[c_cert_file_len] = '\0';
1637 (void) scm_to_locale_stringbuf (key_file, c_key_file, c_key_file_len + 1);
1638 c_key_file[c_key_file_len] = '\0';
1639
1640 err = gnutls_certificate_set_x509_key_file (c_cred, c_cert_file, c_key_file,
1641 c_format);
1642 if (EXPECT_FALSE (err))
1643 scm_gnutls_error (err, FUNC_NAME);
1644
1645 return SCM_UNSPECIFIED;
1646 }
1647
1648 #undef FUNC_NAME
1649
1650 SCM_DEFINE (scm_gnutls_set_certificate_credentials_x509_trust_file_x,
1651 "set-certificate-credentials-x509-trust-file!",
1652 3, 0, 0,
1653 (SCM cred, SCM file, SCM format),
1654 "Use @var{file} as the X.509 trust file for certificate "
1655 "credentials @var{cred}. On success, return the number of "
1656 "certificates processed.")
1657 #define FUNC_NAME s_scm_gnutls_set_certificate_credentials_x509_trust_file_x
1658 {
1659 unsigned int count;
1660
1661 count = set_certificate_file (gnutls_certificate_set_x509_trust_file,
1662 cred, file, format, FUNC_NAME);
1663
1664 return scm_from_uint (count);
1665 }
1666
1667 #undef FUNC_NAME
1668
1669 SCM_DEFINE (scm_gnutls_set_certificate_credentials_x509_crl_file_x,
1670 "set-certificate-credentials-x509-crl-file!",
1671 3, 0, 0,
1672 (SCM cred, SCM file, SCM format),
1673 "Use @var{file} as the X.509 CRL (certificate revocation list) "
1674 "file for certificate credentials @var{cred}. On success, "
1675 "return the number of CRLs processed.")
1676 #define FUNC_NAME s_scm_gnutls_set_certificate_credentials_x509_crl_file_x
1677 {
1678 unsigned int count;
1679
1680 count = set_certificate_file (gnutls_certificate_set_x509_crl_file,
1681 cred, file, format, FUNC_NAME);
1682
1683 return scm_from_uint (count);
1684 }
1685
1686 #undef FUNC_NAME
1687
1688 SCM_DEFINE (scm_gnutls_set_certificate_credentials_x509_trust_data_x,
1689 "set-certificate-credentials-x509-trust-data!",
1690 3, 0, 0,
1691 (SCM cred, SCM data, SCM format),
1692 "Use @var{data} (a uniform array) as the X.509 trust "
1693 "database for @var{cred}. On success, return the number "
1694 "of certificates processed.")
1695 #define FUNC_NAME s_scm_gnutls_set_certificate_credentials_x509_trust_data_x
1696 {
1697 unsigned int count;
1698
1699 count = set_certificate_data (gnutls_certificate_set_x509_trust_mem,
1700 cred, data, format, FUNC_NAME);
1701
1702 return scm_from_uint (count);
1703 }
1704
1705 #undef FUNC_NAME
1706
1707 SCM_DEFINE (scm_gnutls_set_certificate_credentials_x509_crl_data_x,
1708 "set-certificate-credentials-x509-crl-data!",
1709 3, 0, 0,
1710 (SCM cred, SCM data, SCM format),
1711 "Use @var{data} (a uniform array) as the X.509 CRL "
1712 "(certificate revocation list) database for @var{cred}. "
1713 "On success, return the number of CRLs processed.")
1714 #define FUNC_NAME s_scm_gnutls_set_certificate_credentials_x509_crl_data_x
1715 {
1716 unsigned int count;
1717
1718 count = set_certificate_data (gnutls_certificate_set_x509_crl_mem,
1719 cred, data, format, FUNC_NAME);
1720
1721 return scm_from_uint (count);
1722 }
1723
1724 #undef FUNC_NAME
1725
1726 SCM_DEFINE (scm_gnutls_set_certificate_credentials_x509_key_data_x,
1727 "set-certificate-credentials-x509-key-data!",
1728 4, 0, 0,
1729 (SCM cred, SCM cert, SCM key, SCM format),
1730 "Use X.509 certificate @var{cert} and private key @var{key}, "
1731 "both uniform arrays containing the X.509 certificate and key "
1732 "in format @var{format}, for certificate credentials "
1733 "@var{cred}.")
1734 #define FUNC_NAME s_scm_gnutls_set_certificate_credentials_x509_key_data_x
1735 {
1736 int err;
1737 gnutls_x509_crt_fmt_t c_format;
1738 gnutls_certificate_credentials_t c_cred;
1739 gnutls_datum_t c_cert_d, c_key_d;
1740 scm_t_array_handle c_cert_handle, c_key_handle;
1741 const char *c_cert, *c_key;
1742 size_t c_cert_len, c_key_len;
1743
1744 c_cred = scm_to_gnutls_certificate_credentials (cred, 1, FUNC_NAME);
1745 c_format = scm_to_gnutls_x509_certificate_format (format, 4, FUNC_NAME);
1746 SCM_VALIDATE_ARRAY (2, cert);
1747 SCM_VALIDATE_ARRAY (3, key);
1748
1749 /* FIXME: If the second call fails, an exception is raised and
1750 C_CERT_HANDLE is not released. */
1751 c_cert = scm_gnutls_get_array (cert, &c_cert_handle, &c_cert_len,
1752 FUNC_NAME);
1753 c_key = scm_gnutls_get_array (key, &c_key_handle, &c_key_len, FUNC_NAME);
1754
1755 c_cert_d.data = (unsigned char *) c_cert;
1756 c_cert_d.size = c_cert_len;
1757 c_key_d.data = (unsigned char *) c_key;
1758 c_key_d.size = c_key_len;
1759
1760 err = gnutls_certificate_set_x509_key_mem (c_cred, &c_cert_d, &c_key_d,
1761 c_format);
1762 scm_gnutls_release_array (&c_cert_handle);
1763 scm_gnutls_release_array (&c_key_handle);
1764
1765 if (EXPECT_FALSE (err))
1766 scm_gnutls_error (err, FUNC_NAME);
1767
1768 return SCM_UNSPECIFIED;
1769 }
1770
1771 #undef FUNC_NAME
1772
1773 SCM_DEFINE (scm_gnutls_set_certificate_credentials_x509_keys_x,
1774 "set-certificate-credentials-x509-keys!",
1775 3, 0, 0,
1776 (SCM cred, SCM certs, SCM privkey),
1777 "Have certificate credentials @var{cred} use the X.509 "
1778 "certificates listed in @var{certs} and X.509 private key "
1779 "@var{privkey}.")
1780 #define FUNC_NAME s_scm_gnutls_set_certificate_credentials_x509_keys_x
1781 {
1782 int err;
1783 gnutls_x509_crt_t *c_certs;
1784 gnutls_x509_privkey_t c_key;
1785 gnutls_certificate_credentials_t c_cred;
1786 long int c_cert_count, i;
1787
1788 c_cred = scm_to_gnutls_certificate_credentials (cred, 1, FUNC_NAME);
1789 SCM_VALIDATE_LIST_COPYLEN (2, certs, c_cert_count);
1790 c_key = scm_to_gnutls_x509_private_key (privkey, 3, FUNC_NAME);
1791
1792 c_certs = FAST_ALLOC (c_cert_count * sizeof (*c_certs));
1793 for (i = 0; scm_is_pair (certs); certs = SCM_CDR (certs), i++)
1794 {
1795 c_certs[i] = scm_to_gnutls_x509_certificate (SCM_CAR (certs),
1796 2, FUNC_NAME);
1797 }
1798
1799 err = gnutls_certificate_set_x509_key (c_cred, c_certs, c_cert_count,
1800 c_key);
1801 if (EXPECT_FALSE (err))
1802 scm_gnutls_error (err, FUNC_NAME);
1803 else
1804 {
1805 register_weak_reference (cred, privkey);
1806 register_weak_reference (cred, scm_list_copy (certs));
1807 }
1808
1809 return SCM_UNSPECIFIED;
1810 }
1811
1812 #undef FUNC_NAME
1813
1814 SCM_DEFINE (scm_gnutls_set_certificate_credentials_verify_limits_x,
1815 "set-certificate-credentials-verify-limits!",
1816 3, 0, 0,
1817 (SCM cred, SCM max_bits, SCM max_depth),
1818 "Set the verification limits of @code{peer-certificate-status} "
1819 "for certificate credentials @var{cred} to @var{max_bits} "
1820 "bits for an acceptable certificate and @var{max_depth} "
1821 "as the maximum depth of a certificate chain.")
1822 #define FUNC_NAME s_scm_gnutls_set_certificate_credentials_verify_limits_x
1823 {
1824 gnutls_certificate_credentials_t c_cred;
1825 unsigned int c_max_bits, c_max_depth;
1826
1827 c_cred = scm_to_gnutls_certificate_credentials (cred, 1, FUNC_NAME);
1828 c_max_bits = scm_to_uint (max_bits);
1829 c_max_depth = scm_to_uint (max_depth);
1830
1831 gnutls_certificate_set_verify_limits (c_cred, c_max_bits, c_max_depth);
1832
1833 return SCM_UNSPECIFIED;
1834 }
1835
1836 #undef FUNC_NAME
1837
1838 SCM_DEFINE (scm_gnutls_set_certificate_credentials_verify_flags_x,
1839 "set-certificate-credentials-verify-flags!",
1840 1, 0, 1,
1841 (SCM cred, SCM flags),
1842 "Set the certificate verification flags to @var{flags}, a "
1843 "series of @code{certificate-verify} values.")
1844 #define FUNC_NAME s_scm_gnutls_set_certificate_credentials_verify_flags_x
1845 {
1846 unsigned int c_flags, c_pos;
1847 gnutls_certificate_credentials_t c_cred;
1848
1849 c_cred = scm_to_gnutls_certificate_credentials (cred, 1, FUNC_NAME);
1850
1851 for (c_flags = 0, c_pos = 2;
1852 !scm_is_null (flags); flags = SCM_CDR (flags), c_pos++)
1853 {
1854 c_flags |= (unsigned int)
1855 scm_to_gnutls_certificate_verify (SCM_CAR (flags), c_pos, FUNC_NAME);
1856 }
1857
1858 gnutls_certificate_set_verify_flags (c_cred, c_flags);
1859
1860 return SCM_UNSPECIFIED;
1861 }
1862
1863 #undef FUNC_NAME
1864
1865 SCM_DEFINE (scm_gnutls_peer_certificate_status, "peer-certificate-status",
1866 1, 0, 0,
1867 (SCM session),
1868 "Verify the peer certificate for @var{session} and return "
1869 "a list of @code{certificate-status} values (such as "
1870 "@code{certificate-status/revoked}), or the empty list if "
1871 "the certificate is valid.")
1872 #define FUNC_NAME s_scm_gnutls_peer_certificate_status
1873 {
1874 int err;
1875 unsigned int c_status;
1876 gnutls_session_t c_session;
1877 SCM result = SCM_EOL;
1878
1879 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
1880
1881 err = gnutls_certificate_verify_peers2 (c_session, &c_status);
1882 if (EXPECT_FALSE (err))
1883 scm_gnutls_error (err, FUNC_NAME);
1884
1885 #define MATCH_STATUS(_value) \
1886 if (c_status & (_value)) \
1887 { \
1888 result = scm_cons (scm_from_gnutls_certificate_status (_value), \
1889 result); \
1890 c_status &= ~(_value); \
1891 }
1892
1893 MATCH_STATUS (GNUTLS_CERT_INVALID);
1894 MATCH_STATUS (GNUTLS_CERT_REVOKED);
1895 MATCH_STATUS (GNUTLS_CERT_SIGNER_NOT_FOUND);
1896 MATCH_STATUS (GNUTLS_CERT_SIGNER_NOT_CA);
1897 MATCH_STATUS (GNUTLS_CERT_INSECURE_ALGORITHM);
1898 MATCH_STATUS (GNUTLS_CERT_NOT_ACTIVATED);
1899 MATCH_STATUS (GNUTLS_CERT_EXPIRED);
1900 MATCH_STATUS (GNUTLS_CERT_SIGNATURE_FAILURE);
1901 MATCH_STATUS (GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED);
1902 MATCH_STATUS (GNUTLS_CERT_UNEXPECTED_OWNER);
1903 MATCH_STATUS (GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE);
1904 MATCH_STATUS (GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE);
1905 MATCH_STATUS (GNUTLS_CERT_MISMATCH);
1906 MATCH_STATUS (GNUTLS_CERT_PURPOSE_MISMATCH);
1907 MATCH_STATUS (GNUTLS_CERT_MISSING_OCSP_STATUS);
1908 MATCH_STATUS (GNUTLS_CERT_INVALID_OCSP_STATUS);
1909 MATCH_STATUS (GNUTLS_CERT_UNKNOWN_CRIT_EXTENSIONS);
1910
1911 if (EXPECT_FALSE (c_status != 0))
1912 /* XXX: We failed to interpret one of the status flags. */
1913 scm_gnutls_error (GNUTLS_E_UNIMPLEMENTED_FEATURE, FUNC_NAME);
1914
1915 #undef MATCH_STATUS
1916
1917 return (result);
1918 }
1919
1920 #undef FUNC_NAME
1921
1922
1923 /* SRP credentials. */
1924
1925 #ifdef ENABLE_SRP
1926 SCM_DEFINE (scm_gnutls_make_srp_server_credentials,
1927 "make-srp-server-credentials",
1928 0, 0, 0, (void), "Return new SRP server credentials.")
1929 #define FUNC_NAME s_scm_gnutls_make_srp_server_credentials
1930 {
1931 int err;
1932 gnutls_srp_server_credentials_t c_cred;
1933
1934 err = gnutls_srp_allocate_server_credentials (&c_cred);
1935 if (EXPECT_FALSE (err))
1936 scm_gnutls_error (err, FUNC_NAME);
1937
1938 return (scm_from_gnutls_srp_server_credentials (c_cred));
1939 }
1940
1941 #undef FUNC_NAME
1942
1943 SCM_DEFINE (scm_gnutls_set_srp_server_credentials_files_x,
1944 "set-srp-server-credentials-files!",
1945 3, 0, 0,
1946 (SCM cred, SCM password_file, SCM password_conf_file),
1947 "Set the credentials files for @var{cred}, an SRP server "
1948 "credentials object.")
1949 #define FUNC_NAME s_scm_gnutls_set_srp_server_credentials_files_x
1950 {
1951 int err;
1952 gnutls_srp_server_credentials_t c_cred;
1953 char *c_password_file, *c_password_conf_file;
1954 size_t c_password_file_len, c_password_conf_file_len;
1955
1956 c_cred = scm_to_gnutls_srp_server_credentials (cred, 1, FUNC_NAME);
1957 SCM_VALIDATE_STRING (2, password_file);
1958 SCM_VALIDATE_STRING (3, password_conf_file);
1959
1960 c_password_file_len = scm_c_string_length (password_file);
1961 c_password_conf_file_len = scm_c_string_length (password_conf_file);
1962
1963 c_password_file = FAST_ALLOC (c_password_file_len + 1);
1964 c_password_conf_file = FAST_ALLOC (c_password_conf_file_len + 1);
1965
1966 (void) scm_to_locale_stringbuf (password_file, c_password_file,
1967 c_password_file_len + 1);
1968 c_password_file[c_password_file_len] = '\0';
1969 (void) scm_to_locale_stringbuf (password_conf_file, c_password_conf_file,
1970 c_password_conf_file_len + 1);
1971 c_password_conf_file[c_password_conf_file_len] = '\0';
1972
1973 err = gnutls_srp_set_server_credentials_file (c_cred, c_password_file,
1974 c_password_conf_file);
1975 if (EXPECT_FALSE (err))
1976 scm_gnutls_error (err, FUNC_NAME);
1977
1978 return SCM_UNSPECIFIED;
1979 }
1980
1981 #undef FUNC_NAME
1982
1983 SCM_DEFINE (scm_gnutls_make_srp_client_credentials,
1984 "make-srp-client-credentials",
1985 0, 0, 0, (void), "Return new SRP client credentials.")
1986 #define FUNC_NAME s_scm_gnutls_make_srp_client_credentials
1987 {
1988 int err;
1989 gnutls_srp_client_credentials_t c_cred;
1990
1991 err = gnutls_srp_allocate_client_credentials (&c_cred);
1992 if (EXPECT_FALSE (err))
1993 scm_gnutls_error (err, FUNC_NAME);
1994
1995 return (scm_from_gnutls_srp_client_credentials (c_cred));
1996 }
1997
1998 #undef FUNC_NAME
1999
2000
2001 SCM_DEFINE (scm_gnutls_set_srp_client_credentials_x,
2002 "set-srp-client-credentials!",
2003 3, 0, 0,
2004 (SCM cred, SCM username, SCM password),
2005 "Use @var{username} and @var{password} as the credentials "
2006 "for @var{cred}, a client-side SRP credentials object.")
2007 #define FUNC_NAME s_scm_gnutls_make_srp_client_credentials
2008 {
2009 int err;
2010 gnutls_srp_client_credentials_t c_cred;
2011 char *c_username, *c_password;
2012 size_t c_username_len, c_password_len;
2013
2014 c_cred = scm_to_gnutls_srp_client_credentials (cred, 1, FUNC_NAME);
2015 SCM_VALIDATE_STRING (2, username);
2016 SCM_VALIDATE_STRING (3, password);
2017
2018 c_username_len = scm_c_string_length (username);
2019 c_password_len = scm_c_string_length (password);
2020
2021 c_username = FAST_ALLOC (c_username_len + 1);
2022 c_password = FAST_ALLOC (c_password_len + 1);
2023
2024 (void) scm_to_locale_stringbuf (username, c_username, c_username_len + 1);
2025 c_username[c_username_len] = '\0';
2026 (void) scm_to_locale_stringbuf (password, c_password, c_password_len + 1);
2027 c_password[c_password_len] = '\0';
2028
2029 err = gnutls_srp_set_client_credentials (c_cred, c_username, c_password);
2030 if (EXPECT_FALSE (err))
2031 scm_gnutls_error (err, FUNC_NAME);
2032
2033 return SCM_UNSPECIFIED;
2034 }
2035
2036 #undef FUNC_NAME
2037
2038 SCM_DEFINE (scm_gnutls_server_session_srp_username,
2039 "server-session-srp-username",
2040 1, 0, 0,
2041 (SCM session),
2042 "Return the SRP username used in @var{session} (a server-side "
2043 "session).")
2044 #define FUNC_NAME s_scm_gnutls_server_session_srp_username
2045 {
2046 SCM result;
2047 const char *c_username;
2048 gnutls_session_t c_session;
2049
2050 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
2051 c_username = gnutls_srp_server_get_username (c_session);
2052
2053 if (EXPECT_FALSE (c_username == NULL))
2054 result = SCM_BOOL_F;
2055 else
2056 result = scm_from_locale_string (c_username);
2057
2058 return (result);
2059 }
2060
2061 #undef FUNC_NAME
2062
2063 SCM_DEFINE (scm_gnutls_srp_base64_encode, "srp-base64-encode",
2064 1, 0, 0,
2065 (SCM str),
2066 "Encode @var{str} using SRP's base64 algorithm. Return "
2067 "the encoded string.")
2068 #define FUNC_NAME s_scm_gnutls_srp_base64_encode
2069 {
2070 int err;
2071 char *c_str, *c_result;
2072 size_t c_str_len, c_result_len, c_result_actual_len;
2073 gnutls_datum_t c_str_d;
2074
2075 SCM_VALIDATE_STRING (1, str);
2076
2077 c_str_len = scm_c_string_length (str);
2078 c_str = FAST_ALLOC (c_str_len + 1);
2079 (void) scm_to_locale_stringbuf (str, c_str, c_str_len + 1);
2080 c_str[c_str_len] = '\0';
2081
2082 /* Typical size ratio is 4/3 so 3/2 is an upper bound. */
2083 c_result_len = (c_str_len * 3) / 2;
2084 c_result = (char *) scm_malloc (c_result_len);
2085 if (EXPECT_FALSE (c_result == NULL))
2086 scm_gnutls_error (GNUTLS_E_MEMORY_ERROR, FUNC_NAME);
2087
2088 c_str_d.data = (unsigned char *) c_str;
2089 c_str_d.size = c_str_len;
2090
2091 do
2092 {
2093 c_result_actual_len = c_result_len;
2094 err = gnutls_srp_base64_encode (&c_str_d, c_result,
2095 &c_result_actual_len);
2096 if (err == GNUTLS_E_SHORT_MEMORY_BUFFER)
2097 {
2098 char *c_new_buf;
2099
2100 c_new_buf = scm_realloc (c_result, c_result_len * 2);
2101 if (EXPECT_FALSE (c_new_buf == NULL))
2102 {
2103 free (c_result);
2104 scm_gnutls_error (GNUTLS_E_MEMORY_ERROR, FUNC_NAME);
2105 }
2106 else
2107 c_result = c_new_buf, c_result_len *= 2;
2108 }
2109 }
2110 while (EXPECT_FALSE (err == GNUTLS_E_SHORT_MEMORY_BUFFER));
2111
2112 if (EXPECT_FALSE (err))
2113 scm_gnutls_error (err, FUNC_NAME);
2114
2115 if (c_result_actual_len + 1 < c_result_len)
2116 /* Shrink the buffer. */
2117 c_result = scm_realloc (c_result, c_result_actual_len + 1);
2118
2119 c_result[c_result_actual_len] = '\0';
2120
2121 return (scm_take_locale_string (c_result));
2122 }
2123
2124 #undef FUNC_NAME
2125
2126 SCM_DEFINE (scm_gnutls_srp_base64_decode, "srp-base64-decode",
2127 1, 0, 0,
2128 (SCM str),
2129 "Decode @var{str}, an SRP-base64 encoded string, and return "
2130 "the decoded string.")
2131 #define FUNC_NAME s_scm_gnutls_srp_base64_decode
2132 {
2133 int err;
2134 char *c_str, *c_result;
2135 size_t c_str_len, c_result_len, c_result_actual_len;
2136 gnutls_datum_t c_str_d;
2137
2138 SCM_VALIDATE_STRING (1, str);
2139
2140 c_str_len = scm_c_string_length (str);
2141 c_str = FAST_ALLOC (c_str_len + 1);
2142 (void) scm_to_locale_stringbuf (str, c_str, c_str_len + 1);
2143 c_str[c_str_len] = '\0';
2144
2145 /* We assume that the decoded string is smaller than the encoded
2146 string. */
2147 c_result_len = c_str_len;
2148 c_result = FAST_ALLOC (c_result_len + 1);
2149
2150 c_str_d.data = (unsigned char *) c_str;
2151 c_str_d.size = c_str_len;
2152
2153 c_result_actual_len = c_result_len;
2154 err = gnutls_srp_base64_decode (&c_str_d, c_result, &c_result_actual_len);
2155 if (EXPECT_FALSE (err))
2156 scm_gnutls_error (err, FUNC_NAME);
2157
2158 c_result[c_result_actual_len] = '\0';
2159
2160 return (scm_from_locale_string (c_result));
2161 }
2162
2163 #undef FUNC_NAME
2164 #endif /* ENABLE_SRP */
2165
2166
2167 /* PSK credentials. */
2168
2169 SCM_DEFINE (scm_gnutls_make_psk_server_credentials,
2170 "make-psk-server-credentials",
2171 0, 0, 0, (void), "Return new PSK server credentials.")
2172 #define FUNC_NAME s_scm_gnutls_make_psk_server_credentials
2173 {
2174 int err;
2175 gnutls_psk_server_credentials_t c_cred;
2176
2177 err = gnutls_psk_allocate_server_credentials (&c_cred);
2178 if (EXPECT_FALSE (err))
2179 scm_gnutls_error (err, FUNC_NAME);
2180
2181 return (scm_from_gnutls_psk_server_credentials (c_cred));
2182 }
2183
2184 #undef FUNC_NAME
2185
2186 SCM_DEFINE (scm_gnutls_set_psk_server_credentials_file_x,
2187 "set-psk-server-credentials-file!",
2188 2, 0, 0,
2189 (SCM cred, SCM file),
2190 "Use @var{file} as the password file for PSK server "
2191 "credentials @var{cred}.")
2192 #define FUNC_NAME s_scm_gnutls_set_psk_server_credentials_file_x
2193 {
2194 int err;
2195 gnutls_psk_server_credentials_t c_cred;
2196 char *c_file;
2197 size_t c_file_len;
2198
2199 c_cred = scm_to_gnutls_psk_server_credentials (cred, 1, FUNC_NAME);
2200 SCM_VALIDATE_STRING (2, file);
2201
2202 c_file_len = scm_c_string_length (file);
2203 c_file = FAST_ALLOC (c_file_len + 1);
2204
2205 (void) scm_to_locale_stringbuf (file, c_file, c_file_len + 1);
2206 c_file[c_file_len] = '\0';
2207
2208 err = gnutls_psk_set_server_credentials_file (c_cred, c_file);
2209 if (EXPECT_FALSE (err))
2210 scm_gnutls_error (err, FUNC_NAME);
2211
2212 return SCM_UNSPECIFIED;
2213 }
2214
2215 #undef FUNC_NAME
2216
2217 SCM_DEFINE (scm_gnutls_make_psk_client_credentials,
2218 "make-psk-client-credentials",
2219 0, 0, 0, (void), "Return a new PSK client credentials object.")
2220 #define FUNC_NAME s_scm_gnutls_make_psk_client_credentials
2221 {
2222 int err;
2223 gnutls_psk_client_credentials_t c_cred;
2224
2225 err = gnutls_psk_allocate_client_credentials (&c_cred);
2226 if (EXPECT_FALSE (err))
2227 scm_gnutls_error (err, FUNC_NAME);
2228
2229 return (scm_from_gnutls_psk_client_credentials (c_cred));
2230 }
2231
2232 #undef FUNC_NAME
2233
2234 SCM_DEFINE (scm_gnutls_set_psk_client_credentials_x,
2235 "set-psk-client-credentials!",
2236 4, 0, 0,
2237 (SCM cred, SCM username, SCM key, SCM key_format),
2238 "Set the client credentials for @var{cred}, a PSK client "
2239 "credentials object.")
2240 #define FUNC_NAME s_scm_gnutls_set_psk_client_credentials_x
2241 {
2242 int err;
2243 gnutls_psk_client_credentials_t c_cred;
2244 gnutls_psk_key_flags c_key_format;
2245 scm_t_array_handle c_handle;
2246 const char *c_key;
2247 char *c_username;
2248 size_t c_username_len, c_key_len;
2249 gnutls_datum_t c_datum;
2250
2251 c_cred = scm_to_gnutls_psk_client_credentials (cred, 1, FUNC_NAME);
2252 SCM_VALIDATE_STRING (2, username);
2253 SCM_VALIDATE_ARRAY (3, key);
2254 c_key_format = scm_to_gnutls_psk_key_format (key_format, 4, FUNC_NAME);
2255
2256 c_username_len = scm_c_string_length (username);
2257 c_username = FAST_ALLOC (c_username_len + 1);
2258
2259 (void) scm_to_locale_stringbuf (username, c_username, c_username_len + 1);
2260 c_username[c_username_len] = '\0';
2261
2262 c_key = scm_gnutls_get_array (key, &c_handle, &c_key_len, FUNC_NAME);
2263 c_datum.data = (unsigned char *) c_key;
2264 c_datum.size = c_key_len;
2265
2266 err = gnutls_psk_set_client_credentials (c_cred, c_username,
2267 &c_datum, c_key_format);
2268 scm_gnutls_release_array (&c_handle);
2269
2270 if (EXPECT_FALSE (err))
2271 scm_gnutls_error (err, FUNC_NAME);
2272
2273 return SCM_UNSPECIFIED;
2274 }
2275
2276 #undef FUNC_NAME
2277
2278 SCM_DEFINE (scm_gnutls_server_session_psk_username,
2279 "server-session-psk-username",
2280 1, 0, 0,
2281 (SCM session),
2282 "Return the username associated with PSK server session "
2283 "@var{session}.")
2284 #define FUNC_NAME s_scm_gnutls_server_session_psk_username
2285 {
2286 SCM result;
2287 const char *c_username;
2288 gnutls_session_t c_session;
2289
2290 c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
2291 c_username = gnutls_srp_server_get_username (c_session);
2292
2293 if (EXPECT_FALSE (c_username == NULL))
2294 result = SCM_BOOL_F;
2295 else
2296 result = scm_from_locale_string (c_username);
2297
2298 return (result);
2299 }
2300
2301 #undef FUNC_NAME
2302
2303
2304 /* X.509 certificates. */
2305
2306 SCM_DEFINE (scm_gnutls_import_x509_certificate, "import-x509-certificate",
2307 2, 0, 0,
2308 (SCM data, SCM format),
2309 "Return a new X.509 certificate object resulting from the "
2310 "import of @var{data} (a uniform array) according to "
2311 "@var{format}.")
2312 #define FUNC_NAME s_scm_gnutls_import_x509_certificate
2313 {
2314 int err;
2315 gnutls_x509_crt_t c_cert;
2316 gnutls_x509_crt_fmt_t c_format;
2317 gnutls_datum_t c_data_d;
2318 scm_t_array_handle c_data_handle;
2319 const char *c_data;
2320 size_t c_data_len;
2321
2322 SCM_VALIDATE_ARRAY (1, data);
2323 c_format = scm_to_gnutls_x509_certificate_format (format, 2, FUNC_NAME);
2324
2325 c_data = scm_gnutls_get_array (data, &c_data_handle, &c_data_len,
2326 FUNC_NAME);
2327 c_data_d.data = (unsigned char *) c_data;
2328 c_data_d.size = c_data_len;
2329
2330 err = gnutls_x509_crt_init (&c_cert);
2331 if (EXPECT_FALSE (err))
2332 {
2333 scm_gnutls_release_array (&c_data_handle);
2334 scm_gnutls_error (err, FUNC_NAME);
2335 }
2336
2337 err = gnutls_x509_crt_import (c_cert, &c_data_d, c_format);
2338 scm_gnutls_release_array (&c_data_handle);
2339
2340 if (EXPECT_FALSE (err))
2341 {
2342 gnutls_x509_crt_deinit (c_cert);
2343 scm_gnutls_error (err, FUNC_NAME);
2344 }
2345
2346 return (scm_from_gnutls_x509_certificate (c_cert));
2347 }
2348
2349 #undef FUNC_NAME
2350
2351 SCM_DEFINE (scm_gnutls_import_x509_private_key, "import-x509-private-key",
2352 2, 0, 0,
2353 (SCM data, SCM format),
2354 "Return a new X.509 private key object resulting from the "
2355 "import of @var{data} (a uniform array) according to "
2356 "@var{format}.")
2357 #define FUNC_NAME s_scm_gnutls_import_x509_private_key
2358 {
2359 int err;
2360 gnutls_x509_privkey_t c_key;
2361 gnutls_x509_crt_fmt_t c_format;
2362 gnutls_datum_t c_data_d;
2363 scm_t_array_handle c_data_handle;
2364 const char *c_data;
2365 size_t c_data_len;
2366
2367 SCM_VALIDATE_ARRAY (1, data);
2368 c_format = scm_to_gnutls_x509_certificate_format (format, 2, FUNC_NAME);
2369
2370 c_data = scm_gnutls_get_array (data, &c_data_handle, &c_data_len,
2371 FUNC_NAME);
2372 c_data_d.data = (unsigned char *) c_data;
2373 c_data_d.size = c_data_len;
2374
2375 err = gnutls_x509_privkey_init (&c_key);
2376 if (EXPECT_FALSE (err))
2377 {
2378 scm_gnutls_release_array (&c_data_handle);
2379 scm_gnutls_error (err, FUNC_NAME);
2380 }
2381
2382 err = gnutls_x509_privkey_import (c_key, &c_data_d, c_format);
2383 scm_gnutls_release_array (&c_data_handle);
2384
2385 if (EXPECT_FALSE (err))
2386 {
2387 gnutls_x509_privkey_deinit (c_key);
2388 scm_gnutls_error (err, FUNC_NAME);
2389 }
2390
2391 return (scm_from_gnutls_x509_private_key (c_key));
2392 }
2393
2394 #undef FUNC_NAME
2395
2396 SCM_DEFINE (scm_gnutls_pkcs8_import_x509_private_key,
2397 "pkcs8-import-x509-private-key",
2398 2, 2, 0,
2399 (SCM data, SCM format, SCM pass, SCM encrypted),
2400 "Return a new X.509 private key object resulting from the "
2401 "import of @var{data} (a uniform array) according to "
2402 "@var{format}. Optionally, if @var{pass} is not @code{#f}, "
2403 "it should be a string denoting a passphrase. "
2404 "@var{encrypted} tells whether the private key is encrypted "
2405 "(@code{#t} by default).")
2406 #define FUNC_NAME s_scm_gnutls_pkcs8_import_x509_private_key
2407 {
2408 int err;
2409 gnutls_x509_privkey_t c_key;
2410 gnutls_x509_crt_fmt_t c_format;
2411 unsigned int c_flags;
2412 gnutls_datum_t c_data_d;
2413 scm_t_array_handle c_data_handle;
2414 const char *c_data;
2415 char *c_pass;
2416 size_t c_data_len, c_pass_len;
2417
2418 SCM_VALIDATE_ARRAY (1, data);
2419 c_format = scm_to_gnutls_x509_certificate_format (format, 2, FUNC_NAME);
2420 if ((pass == SCM_UNDEFINED) || (scm_is_false (pass)))
2421 c_pass = NULL;
2422 else
2423 {
2424 c_pass_len = scm_c_string_length (pass);
2425 c_pass = FAST_ALLOC (c_pass_len + 1);
2426 (void) scm_to_locale_stringbuf (pass, c_pass, c_pass_len + 1);
2427 c_pass[c_pass_len] = '\0';
2428 }
2429
2430 if (encrypted == SCM_UNDEFINED)
2431 c_flags = 0;
2432 else
2433 {
2434 SCM_VALIDATE_BOOL (4, encrypted);
2435 if (scm_is_true (encrypted))
2436 c_flags = 0;
2437 else
2438 c_flags = GNUTLS_PKCS8_PLAIN;
2439 }
2440
2441 c_data = scm_gnutls_get_array (data, &c_data_handle, &c_data_len,
2442 FUNC_NAME);
2443 c_data_d.data = (unsigned char *) c_data;
2444 c_data_d.size = c_data_len;
2445
2446 err = gnutls_x509_privkey_init (&c_key);
2447 if (EXPECT_FALSE (err))
2448 {
2449 scm_gnutls_release_array (&c_data_handle);
2450 scm_gnutls_error (err, FUNC_NAME);
2451 }
2452
2453 err = gnutls_x509_privkey_import_pkcs8 (c_key, &c_data_d, c_format, c_pass,
2454 c_flags);
2455 scm_gnutls_release_array (&c_data_handle);
2456
2457 if (EXPECT_FALSE (err))
2458 {
2459 gnutls_x509_privkey_deinit (c_key);
2460 scm_gnutls_error (err, FUNC_NAME);
2461 }
2462
2463 return (scm_from_gnutls_x509_private_key (c_key));
2464 }
2465
2466 #undef FUNC_NAME
2467
2468 /* Provide the body of a `get_dn' function. */
2469 #define X509_CERTIFICATE_DN_FUNCTION_BODY(get_the_dn) \
2470 int err; \
2471 gnutls_x509_crt_t c_cert; \
2472 char *c_dn; \
2473 size_t c_dn_len; \
2474 \
2475 c_cert = scm_to_gnutls_x509_certificate (cert, 1, FUNC_NAME); \
2476 \
2477 /* Get the DN size. */ \
2478 (void) get_the_dn (c_cert, NULL, &c_dn_len); \
2479 \
2480 /* Get the DN itself. */ \
2481 c_dn = FAST_ALLOC (c_dn_len); \
2482 err = get_the_dn (c_cert, c_dn, &c_dn_len); \
2483 \
2484 if (EXPECT_FALSE (err)) \
2485 scm_gnutls_error (err, FUNC_NAME); \
2486 \
2487 /* XXX: The returned string is actually ASCII or UTF-8. */ \
2488 return (scm_from_locale_string (c_dn));
2489
2490 SCM_DEFINE (scm_gnutls_x509_certificate_dn, "x509-certificate-dn",
2491 1, 0, 0,
2492 (SCM cert),
2493 "Return the distinguished name (DN) of X.509 certificate "
2494 "@var{cert}. The form of the DN is as described in @uref{"
2495 "https://tools.ietf.org/html/rfc2253, RFC 2253}.")
2496 #define FUNC_NAME s_scm_gnutls_x509_certificate_dn
2497 {
2498 X509_CERTIFICATE_DN_FUNCTION_BODY (gnutls_x509_crt_get_dn);
2499 }
2500
2501 #undef FUNC_NAME
2502
2503 SCM_DEFINE (scm_gnutls_x509_certificate_issuer_dn,
2504 "x509-certificate-issuer-dn",
2505 1, 0, 0,
2506 (SCM cert),
2507 "Return the distinguished name (DN) of X.509 certificate "
2508 "@var{cert}.")
2509 #define FUNC_NAME s_scm_gnutls_x509_certificate_issuer_dn
2510 {
2511 X509_CERTIFICATE_DN_FUNCTION_BODY (gnutls_x509_crt_get_issuer_dn);
2512 }
2513
2514 #undef FUNC_NAME
2515
2516 #undef X509_CERTIFICATE_DN_FUNCTION_BODY
2517
2518
2519 /* Provide the body of a `get_dn_oid' function. */
2520 #define X509_CERTIFICATE_DN_OID_FUNCTION_BODY(get_dn_oid) \
2521 int err; \
2522 gnutls_x509_crt_t c_cert; \
2523 unsigned int c_index; \
2524 char *c_oid; \
2525 size_t c_oid_actual_len, c_oid_len; \
2526 SCM result; \
2527 \
2528 c_cert = scm_to_gnutls_x509_certificate (cert, 1, FUNC_NAME); \
2529 c_index = scm_to_uint (index); \
2530 \
2531 c_oid_len = 256; \
2532 c_oid = scm_malloc (c_oid_len); \
2533 \
2534 do \
2535 { \
2536 c_oid_actual_len = c_oid_len; \
2537 err = get_dn_oid (c_cert, c_index, c_oid, &c_oid_actual_len); \
2538 if (err == GNUTLS_E_SHORT_MEMORY_BUFFER) \
2539 { \
2540 c_oid = scm_realloc (c_oid, c_oid_len * 2); \
2541 c_oid_len *= 2; \
2542 } \
2543 } \
2544 while (err == GNUTLS_E_SHORT_MEMORY_BUFFER); \
2545 \
2546 if (EXPECT_FALSE (err)) \
2547 { \
2548 free (c_oid); \
2549 \
2550 if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) \
2551 result = SCM_BOOL_F; \
2552 else \
2553 scm_gnutls_error (err, FUNC_NAME); \
2554 } \
2555 else \
2556 { \
2557 if (c_oid_actual_len < c_oid_len) \
2558 c_oid = scm_realloc (c_oid, c_oid_actual_len); \
2559 \
2560 result = scm_take_locale_stringn (c_oid, \
2561 c_oid_actual_len); \
2562 } \
2563 \
2564 return result;
2565
2566 SCM_DEFINE (scm_gnutls_x509_certificate_dn_oid, "x509-certificate-dn-oid",
2567 2, 0, 0,
2568 (SCM cert, SCM index),
2569 "Return OID (a string) at @var{index} from @var{cert}. "
2570 "Return @code{#f} if no OID is available at @var{index}.")
2571 #define FUNC_NAME s_scm_gnutls_x509_certificate_dn_oid
2572 {
2573 X509_CERTIFICATE_DN_OID_FUNCTION_BODY (gnutls_x509_crt_get_dn_oid);
2574 }
2575
2576 #undef FUNC_NAME
2577
2578 SCM_DEFINE (scm_gnutls_x509_certificate_issuer_dn_oid,
2579 "x509-certificate-issuer-dn-oid",
2580 2, 0, 0,
2581 (SCM cert, SCM index),
2582 "Return the OID (a string) at @var{index} from @var{cert}'s "
2583 "issuer DN. Return @code{#f} if no OID is available at "
2584 "@var{index}.")
2585 #define FUNC_NAME s_scm_gnutls_x509_certificate_issuer_dn_oid
2586 {
2587 X509_CERTIFICATE_DN_OID_FUNCTION_BODY (gnutls_x509_crt_get_issuer_dn_oid);
2588 }
2589
2590 #undef FUNC_NAME
2591
2592 #undef X509_CERTIFICATE_DN_OID_FUNCTION_BODY
2593
2594
2595 SCM_DEFINE (scm_gnutls_x509_certificate_matches_hostname_p,
2596 "x509-certificate-matches-hostname?",
2597 2, 0, 0,
2598 (SCM cert, SCM hostname),
2599 "Return true if @var{cert} matches @var{hostname}, a string "
2600 "denoting a DNS host name. This is the basic implementation "
2601 "of @uref{https://tools.ietf.org/html/rfc2818, RFC 2818} (aka. "
2602 "HTTPS).")
2603 #define FUNC_NAME s_scm_gnutls_x509_certificate_matches_hostname_p
2604 {
2605 SCM result;
2606 gnutls_x509_crt_t c_cert;
2607 char *c_hostname;
2608 size_t c_hostname_len;
2609
2610 c_cert = scm_to_gnutls_x509_certificate (cert, 1, FUNC_NAME);
2611 SCM_VALIDATE_STRING (2, hostname);
2612
2613 c_hostname_len = scm_c_string_length (hostname);
2614 c_hostname = FAST_ALLOC (c_hostname_len + 1);
2615
2616 (void) scm_to_locale_stringbuf (hostname, c_hostname, c_hostname_len + 1);
2617 c_hostname[c_hostname_len] = '\0';
2618
2619 if (gnutls_x509_crt_check_hostname (c_cert, c_hostname))
2620 result = SCM_BOOL_T;
2621 else
2622 result = SCM_BOOL_F;
2623
2624 return result;
2625 }
2626
2627 #undef FUNC_NAME
2628
2629 SCM_DEFINE (scm_gnutls_x509_certificate_signature_algorithm,
2630 "x509-certificate-signature-algorithm",
2631 1, 0, 0,
2632 (SCM cert),
2633 "Return the signature algorithm used by @var{cert} (i.e., "
2634 "one of the @code{sign-algorithm/} values).")
2635 #define FUNC_NAME s_scm_gnutls_x509_certificate_signature_algorithm
2636 {
2637 int c_result;
2638 gnutls_x509_crt_t c_cert;
2639
2640 c_cert = scm_to_gnutls_x509_certificate (cert, 1, FUNC_NAME);
2641
2642 c_result = gnutls_x509_crt_get_signature_algorithm (c_cert);
2643 if (EXPECT_FALSE (c_result < 0))
2644 scm_gnutls_error (c_result, FUNC_NAME);
2645
2646 return (scm_from_gnutls_sign_algorithm (c_result));
2647 }
2648
2649 #undef FUNC_NAME
2650
2651 SCM_DEFINE (scm_gnutls_x509_certificate_public_key_algorithm,
2652 "x509-certificate-public-key-algorithm",
2653 1, 0, 0,
2654 (SCM cert),
2655 "Return two values: the public key algorithm (i.e., "
2656 "one of the @code{pk-algorithm/} values) of @var{cert} "
2657 "and the number of bits used.")
2658 #define FUNC_NAME s_scm_gnutls_x509_certificate_public_key_algorithm
2659 {
2660 gnutls_x509_crt_t c_cert;
2661 gnutls_pk_algorithm_t c_pk;
2662 unsigned int c_bits;
2663
2664 c_cert = scm_to_gnutls_x509_certificate (cert, 1, FUNC_NAME);
2665
2666 c_pk = gnutls_x509_crt_get_pk_algorithm (c_cert, &c_bits);
2667
2668 return (scm_values (scm_list_2 (scm_from_gnutls_pk_algorithm (c_pk),
2669 scm_from_uint (c_bits))));
2670 }
2671
2672 #undef FUNC_NAME
2673
2674 SCM_DEFINE (scm_gnutls_x509_certificate_key_usage,
2675 "x509-certificate-key-usage",
2676 1, 0, 0,
2677 (SCM cert),
2678 "Return the key usage of @var{cert} (i.e., a list of "
2679 "@code{key-usage/} values), or the empty list if @var{cert} "
2680 "does not contain such information.")
2681 #define FUNC_NAME s_scm_gnutls_x509_certificate_key_usage
2682 {
2683 int err;
2684 SCM usage;
2685 gnutls_x509_crt_t c_cert;
2686 unsigned int c_usage, c_critical;
2687
2688 c_cert = scm_to_gnutls_x509_certificate (cert, 1, FUNC_NAME);
2689
2690 err = gnutls_x509_crt_get_key_usage (c_cert, &c_usage, &c_critical);
2691 if (EXPECT_FALSE (err))
2692 {
2693 if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
2694 usage = SCM_EOL;
2695 else
2696 scm_gnutls_error (err, FUNC_NAME);
2697 }
2698 else
2699 usage = scm_from_gnutls_key_usage_flags (c_usage);
2700
2701 return usage;
2702 }
2703
2704 #undef FUNC_NAME
2705
2706 SCM_DEFINE (scm_gnutls_x509_certificate_version, "x509-certificate-version",
2707 1, 0, 0, (SCM cert), "Return the version of @var{cert}.")
2708 #define FUNC_NAME s_scm_gnutls_x509_certificate_version
2709 {
2710 int c_result;
2711 gnutls_x509_crt_t c_cert;
2712
2713 c_cert = scm_to_gnutls_x509_certificate (cert, 1, FUNC_NAME);
2714
2715 c_result = gnutls_x509_crt_get_version (c_cert);
2716 if (EXPECT_FALSE (c_result < 0))
2717 scm_gnutls_error (c_result, FUNC_NAME);
2718
2719 return (scm_from_int (c_result));
2720 }
2721
2722 #undef FUNC_NAME
2723
2724 SCM_DEFINE (scm_gnutls_x509_certificate_key_id, "x509-certificate-key-id",
2725 1, 0, 0,
2726 (SCM cert),
2727 "Return a statistically unique ID (a u8vector) for @var{cert} "
2728 "that depends on its public key parameters. This is normally "
2729 "a 20-byte SHA-1 hash.")
2730 #define FUNC_NAME s_scm_gnutls_x509_certificate_key_id
2731 {
2732 int err;
2733 SCM result;
2734 scm_t_array_handle c_id_handle;
2735 gnutls_x509_crt_t c_cert;
2736 scm_t_uint8 *c_id;
2737 size_t c_id_len = 20;
2738
2739 c_cert = scm_to_gnutls_x509_certificate (cert, 1, FUNC_NAME);
2740
2741 result = scm_make_u8vector (scm_from_uint (c_id_len), SCM_INUM0);
2742 scm_array_get_handle (result, &c_id_handle);
2743 c_id = scm_array_handle_u8_writable_elements (&c_id_handle);
2744
2745 err = gnutls_x509_crt_get_key_id (c_cert, 0, c_id, &c_id_len);
2746 scm_array_handle_release (&c_id_handle);
2747
2748 if (EXPECT_FALSE (err))
2749 scm_gnutls_error (err, FUNC_NAME);
2750
2751 return result;
2752 }
2753
2754 #undef FUNC_NAME
2755
2756 SCM_DEFINE (scm_gnutls_x509_certificate_authority_key_id,
2757 "x509-certificate-authority-key-id",
2758 1, 0, 0,
2759 (SCM cert),
2760 "Return the key ID (a u8vector) of the X.509 certificate "
2761 "authority of @var{cert}.")
2762 #define FUNC_NAME s_scm_gnutls_x509_certificate_authority_key_id
2763 {
2764 int err;
2765 SCM result;
2766 scm_t_array_handle c_id_handle;
2767 gnutls_x509_crt_t c_cert;
2768 scm_t_uint8 *c_id;
2769 size_t c_id_len = 20;
2770
2771 c_cert = scm_to_gnutls_x509_certificate (cert, 1, FUNC_NAME);
2772
2773 result = scm_make_u8vector (scm_from_uint (c_id_len), SCM_INUM0);
2774 scm_array_get_handle (result, &c_id_handle);
2775 c_id = scm_array_handle_u8_writable_elements (&c_id_handle);
2776
2777 err = gnutls_x509_crt_get_authority_key_id (c_cert, c_id, &c_id_len, NULL);
2778 scm_array_handle_release (&c_id_handle);
2779
2780 if (EXPECT_FALSE (err))
2781 scm_gnutls_error (err, FUNC_NAME);
2782
2783 return result;
2784 }
2785
2786 #undef FUNC_NAME
2787
2788 SCM_DEFINE (scm_gnutls_x509_certificate_subject_key_id,
2789 "x509-certificate-subject-key-id",
2790 1, 0, 0,
2791 (SCM cert),
2792 "Return the subject key ID (a u8vector) for @var{cert}.")
2793 #define FUNC_NAME s_scm_gnutls_x509_certificate_subject_key_id
2794 {
2795 int err;
2796 SCM result;
2797 scm_t_array_handle c_id_handle;
2798 gnutls_x509_crt_t c_cert;
2799 scm_t_uint8 *c_id;
2800 size_t c_id_len = 20;
2801
2802 c_cert = scm_to_gnutls_x509_certificate (cert, 1, FUNC_NAME);
2803
2804 result = scm_make_u8vector (scm_from_uint (c_id_len), SCM_INUM0);
2805 scm_array_get_handle (result, &c_id_handle);
2806 c_id = scm_array_handle_u8_writable_elements (&c_id_handle);
2807
2808 err = gnutls_x509_crt_get_subject_key_id (c_cert, c_id, &c_id_len, NULL);
2809 scm_array_handle_release (&c_id_handle);
2810
2811 if (EXPECT_FALSE (err))
2812 scm_gnutls_error (err, FUNC_NAME);
2813
2814 return result;
2815 }
2816
2817 #undef FUNC_NAME
2818
2819 SCM_DEFINE (scm_gnutls_x509_certificate_subject_alternative_name,
2820 "x509-certificate-subject-alternative-name",
2821 2, 0, 0,
2822 (SCM cert, SCM index),
2823 "Return two values: the alternative name type for @var{cert} "
2824 "(i.e., one of the @code{x509-subject-alternative-name/} values) "
2825 "and the actual subject alternative name (a string) at "
2826 "@var{index}. Both values are @code{#f} if no alternative name "
2827 "is available at @var{index}.")
2828 #define FUNC_NAME s_scm_gnutls_x509_certificate_subject_alternative_name
2829 {
2830 int err;
2831 SCM result;
2832 gnutls_x509_crt_t c_cert;
2833 unsigned int c_index;
2834 char *c_name;
2835 size_t c_name_len = 512, c_name_actual_len;
2836
2837 c_cert = scm_to_gnutls_x509_certificate (cert, 1, FUNC_NAME);
2838 c_index = scm_to_uint (index);
2839
2840 c_name = scm_malloc (c_name_len);
2841 do
2842 {
2843 c_name_actual_len = c_name_len;
2844 err = gnutls_x509_crt_get_subject_alt_name (c_cert, c_index,
2845 c_name, &c_name_actual_len,
2846 NULL);
2847 if (err == GNUTLS_E_SHORT_MEMORY_BUFFER)
2848 {
2849 c_name = scm_realloc (c_name, c_name_len * 2);
2850 c_name_len *= 2;
2851 }
2852 }
2853 while (err == GNUTLS_E_SHORT_MEMORY_BUFFER);
2854
2855 if (EXPECT_FALSE (err < 0))
2856 {
2857 free (c_name);
2858
2859 if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
2860 result = scm_values (scm_list_2 (SCM_BOOL_F, SCM_BOOL_F));
2861 else
2862 scm_gnutls_error (err, FUNC_NAME);
2863 }
2864 else
2865 {
2866 if (c_name_actual_len < c_name_len)
2867 c_name = scm_realloc (c_name, c_name_actual_len);
2868
2869 result =
2870 scm_values (scm_list_2
2871 (scm_from_gnutls_x509_subject_alternative_name (err),
2872 scm_take_locale_string (c_name)));
2873 }
2874
2875 return result;
2876 }
2877
2878 #undef FUNC_NAME
2879
2880
2881 /* OpenPGP keys. */
2882
2883
2884 /* Maximum size we support for the name of OpenPGP keys. */
2885 #define GUILE_GNUTLS_MAX_OPENPGP_NAME_LENGTH 2048
2886
2887 SCM_DEFINE (scm_gnutls_import_openpgp_certificate,
2888 "%import-openpgp-certificate", 2, 0, 0, (SCM data, SCM format),
2889 "Return a new OpenPGP certificate object resulting from the "
2890 "import of @var{data} (a uniform array) according to "
2891 "@var{format}.")
2892 #define FUNC_NAME s_scm_gnutls_import_openpgp_certificate
2893 {
2894 int err;
2895 gnutls_openpgp_crt_t c_key;
2896 gnutls_openpgp_crt_fmt_t c_format;
2897 gnutls_datum_t c_data_d;
2898 scm_t_array_handle c_data_handle;
2899 const char *c_data;
2900 size_t c_data_len;
2901
2902 SCM_VALIDATE_ARRAY (1, data);
2903 c_format = scm_to_gnutls_openpgp_certificate_format (format, 2, FUNC_NAME);
2904
2905 c_data = scm_gnutls_get_array (data, &c_data_handle, &c_data_len,
2906 FUNC_NAME);
2907 c_data_d.data = (unsigned char *) c_data;
2908 c_data_d.size = c_data_len;
2909
2910 err = gnutls_openpgp_crt_init (&c_key);
2911 if (EXPECT_FALSE (err))
2912 {
2913 scm_gnutls_release_array (&c_data_handle);
2914 scm_gnutls_error (err, FUNC_NAME);
2915 }
2916
2917 err = gnutls_openpgp_crt_import (c_key, &c_data_d, c_format);
2918 scm_gnutls_release_array (&c_data_handle);
2919
2920 if (EXPECT_FALSE (err))
2921 {
2922 gnutls_openpgp_crt_deinit (c_key);
2923 scm_gnutls_error (err, FUNC_NAME);
2924 }
2925
2926 return (scm_from_gnutls_openpgp_certificate (c_key));
2927 }
2928
2929 #undef FUNC_NAME
2930
2931 SCM_DEFINE (scm_gnutls_import_openpgp_private_key,
2932 "%import-openpgp-private-key", 2, 1, 0, (SCM data, SCM format,
2933 SCM pass),
2934 "Return a new OpenPGP private key object resulting from the "
2935 "import of @var{data} (a uniform array) according to "
2936 "@var{format}. Optionally, a passphrase may be provided.")
2937 #define FUNC_NAME s_scm_gnutls_import_openpgp_private_key
2938 {
2939 int err;
2940 gnutls_openpgp_privkey_t c_key;
2941 gnutls_openpgp_crt_fmt_t c_format;
2942 gnutls_datum_t c_data_d;
2943 scm_t_array_handle c_data_handle;
2944 const char *c_data;
2945 char *c_pass;
2946 size_t c_data_len, c_pass_len;
2947
2948 SCM_VALIDATE_ARRAY (1, data);
2949 c_format = scm_to_gnutls_openpgp_certificate_format (format, 2, FUNC_NAME);
2950 if ((pass == SCM_UNDEFINED) || (scm_is_false (pass)))
2951 c_pass = NULL;
2952 else
2953 {
2954 c_pass_len = scm_c_string_length (pass);
2955 c_pass = FAST_ALLOC (c_pass_len + 1);
2956 (void) scm_to_locale_stringbuf (pass, c_pass, c_pass_len + 1);
2957 c_pass[c_pass_len] = '\0';
2958 }
2959
2960 c_data = scm_gnutls_get_array (data, &c_data_handle, &c_data_len,
2961 FUNC_NAME);
2962 c_data_d.data = (unsigned char *) c_data;
2963 c_data_d.size = c_data_len;
2964
2965 err = gnutls_openpgp_privkey_init (&c_key);
2966 if (EXPECT_FALSE (err))
2967 {
2968 scm_gnutls_release_array (&c_data_handle);
2969 scm_gnutls_error (err, FUNC_NAME);
2970 }
2971
2972 err = gnutls_openpgp_privkey_import (c_key, &c_data_d, c_format, c_pass,
2973 0 /* currently unused */ );
2974 scm_gnutls_release_array (&c_data_handle);
2975
2976 if (EXPECT_FALSE (err))
2977 {
2978 gnutls_openpgp_privkey_deinit (c_key);
2979 scm_gnutls_error (err, FUNC_NAME);
2980 }
2981
2982 return (scm_from_gnutls_openpgp_private_key (c_key));
2983 }
2984
2985 #undef FUNC_NAME
2986
2987 SCM_DEFINE (scm_gnutls_openpgp_certificate_id, "%openpgp-certificate-id",
2988 1, 0, 0,
2989 (SCM key),
2990 "Return the ID (an 8-element u8vector) of certificate "
2991 "@var{key}.")
2992 #define FUNC_NAME s_scm_gnutls_openpgp_certificate_id
2993 {
2994 int err;
2995 unsigned char *c_id;
2996 gnutls_openpgp_crt_t c_key;
2997
2998 c_key = scm_to_gnutls_openpgp_certificate (key, 1, FUNC_NAME);
2999
3000 c_id = (unsigned char *) malloc (8);
3001 if (c_id == NULL)
3002 scm_gnutls_error (GNUTLS_E_MEMORY_ERROR, FUNC_NAME);
3003
3004 err = gnutls_openpgp_crt_get_key_id (c_key, c_id);
3005 if (EXPECT_FALSE (err))
3006 scm_gnutls_error (err, FUNC_NAME);
3007
3008 return (scm_take_u8vector (c_id, 8));
3009 }
3010
3011 #undef FUNC_NAME
3012
3013 SCM_DEFINE (scm_gnutls_openpgp_certificate_id_x, "%openpgp-certificate-id!",
3014 2, 0, 0,
3015 (SCM key, SCM id),
3016 "Store the ID (an 8 byte sequence) of certificate "
3017 "@var{key} in @var{id} (a u8vector).")
3018 #define FUNC_NAME s_scm_gnutls_openpgp_certificate_id_x
3019 {
3020 int err;
3021 char *c_id;
3022 scm_t_array_handle c_id_handle;
3023 size_t c_id_size;
3024 gnutls_openpgp_crt_t c_key;
3025
3026 c_key = scm_to_gnutls_openpgp_certificate (key, 1, FUNC_NAME);
3027 c_id = scm_gnutls_get_writable_array (id, &c_id_handle, &c_id_size,
3028 FUNC_NAME);
3029
3030 if (EXPECT_FALSE (c_id_size < 8))
3031 {
3032 scm_gnutls_release_array (&c_id_handle);
3033 scm_misc_error (FUNC_NAME, "ID vector too small: ~A", scm_list_1 (id));
3034 }
3035
3036 err = gnutls_openpgp_crt_get_key_id (c_key, (unsigned char *) c_id);
3037 scm_gnutls_release_array (&c_id_handle);
3038
3039 if (EXPECT_FALSE (err))
3040 scm_gnutls_error (err, FUNC_NAME);
3041
3042 return SCM_UNSPECIFIED;
3043 }
3044
3045 #undef FUNC_NAME
3046
3047 SCM_DEFINE (scm_gnutls_openpgp_certificate_fingerpint_x,
3048 "%openpgp-certificate-fingerprint!",
3049 2, 0, 0,
3050 (SCM key, SCM fpr),
3051 "Store in @var{fpr} (a u8vector) the fingerprint of @var{key}. "
3052 "Return the number of bytes stored in @var{fpr}.")
3053 #define FUNC_NAME s_scm_gnutls_openpgp_certificate_fingerpint_x
3054 {
3055 int err;
3056 gnutls_openpgp_crt_t c_key;
3057 char *c_fpr;
3058 scm_t_array_handle c_fpr_handle;
3059 size_t c_fpr_len, c_actual_len = 0;
3060
3061 c_key = scm_to_gnutls_openpgp_certificate (key, 1, FUNC_NAME);
3062 SCM_VALIDATE_ARRAY (2, fpr);
3063
3064 c_fpr = scm_gnutls_get_writable_array (fpr, &c_fpr_handle, &c_fpr_len,
3065 FUNC_NAME);
3066
3067 err = gnutls_openpgp_crt_get_fingerprint (c_key, c_fpr, &c_actual_len);
3068 scm_gnutls_release_array (&c_fpr_handle);
3069
3070 if (EXPECT_FALSE (err))
3071 scm_gnutls_error (err, FUNC_NAME);
3072
3073 return (scm_from_size_t (c_actual_len));
3074 }
3075
3076 #undef FUNC_NAME
3077
3078 SCM_DEFINE (scm_gnutls_openpgp_certificate_fingerprint,
3079 "%openpgp-certificate-fingerprint",
3080 1, 0, 0,
3081 (SCM key),
3082 "Return a new u8vector denoting the fingerprint of " "@var{key}.")
3083 #define FUNC_NAME s_scm_gnutls_openpgp_certificate_fingerprint
3084 {
3085 int err;
3086 gnutls_openpgp_crt_t c_key;
3087 unsigned char *c_fpr;
3088 size_t c_fpr_len, c_actual_len;
3089
3090 c_key = scm_to_gnutls_openpgp_certificate (key, 1, FUNC_NAME);
3091
3092 /* V4 fingerprints are 160-bit SHA-1 hashes (see RFC2440). */
3093 c_fpr_len = 20;
3094 c_fpr = (unsigned char *) malloc (c_fpr_len);
3095 if (EXPECT_FALSE (c_fpr == NULL))
3096 scm_gnutls_error (GNUTLS_E_MEMORY_ERROR, FUNC_NAME);
3097
3098 do
3099 {
3100 c_actual_len = 0;
3101 err = gnutls_openpgp_crt_get_fingerprint (c_key, c_fpr, &c_actual_len);
3102 if (err == GNUTLS_E_SHORT_MEMORY_BUFFER)
3103 {
3104 /* Grow C_FPR. */
3105 unsigned char *c_new;
3106
3107 c_new = (unsigned char *) realloc (c_fpr, c_fpr_len * 2);
3108 if (EXPECT_FALSE (c_new == NULL))
3109 {
3110 free (c_fpr);
3111 scm_gnutls_error (GNUTLS_E_MEMORY_ERROR, FUNC_NAME);
3112 }
3113 else
3114 {
3115 c_fpr_len *= 2;
3116 c_fpr = c_new;
3117 }
3118 }
3119 }
3120 while (err == GNUTLS_E_SHORT_MEMORY_BUFFER);
3121
3122 if (EXPECT_FALSE (err))
3123 {
3124 free (c_fpr);
3125 scm_gnutls_error (err, FUNC_NAME);
3126 }
3127
3128 if (c_actual_len < c_fpr_len)
3129 /* Shrink C_FPR. */
3130 c_fpr = realloc (c_fpr, c_actual_len);
3131
3132 return (scm_take_u8vector (c_fpr, c_actual_len));
3133 }
3134
3135 #undef FUNC_NAME
3136
3137 SCM_DEFINE (scm_gnutls_openpgp_certificate_name, "%openpgp-certificate-name",
3138 2, 0, 0,
3139 (SCM key, SCM index),
3140 "Return the @var{index}th name of @var{key}.")
3141 #define FUNC_NAME s_scm_gnutls_openpgp_certificate_name
3142 {
3143 int err;
3144 gnutls_openpgp_crt_t c_key;
3145 int c_index;
3146 char c_name[GUILE_GNUTLS_MAX_OPENPGP_NAME_LENGTH];
3147 size_t c_name_len = sizeof (c_name);
3148
3149 c_key = scm_to_gnutls_openpgp_certificate (key, 1, FUNC_NAME);
3150 c_index = scm_to_int (index);
3151
3152 err = gnutls_openpgp_crt_get_name (c_key, c_index, c_name, &c_name_len);
3153 if (EXPECT_FALSE (err))
3154 scm_gnutls_error (err, FUNC_NAME);
3155
3156 /* XXX: The name is really UTF-8. */
3157 return (scm_from_locale_string (c_name));
3158 }
3159
3160 #undef FUNC_NAME
3161
3162 SCM_DEFINE (scm_gnutls_openpgp_certificate_names, "%openpgp-certificate-names",
3163 1, 0, 0, (SCM key), "Return the list of names for @var{key}.")
3164 #define FUNC_NAME s_scm_gnutls_openpgp_certificate_names
3165 {
3166 int err;
3167 SCM result = SCM_EOL;
3168 gnutls_openpgp_crt_t c_key;
3169 int c_index = 0;
3170 char c_name[GUILE_GNUTLS_MAX_OPENPGP_NAME_LENGTH];
3171 size_t c_name_len = sizeof (c_name);
3172
3173 c_key = scm_to_gnutls_openpgp_certificate (key, 1, FUNC_NAME);
3174
3175 do
3176 {
3177 err = gnutls_openpgp_crt_get_name (c_key, c_index, c_name, &c_name_len);
3178 if (!err)
3179 {
3180 result = scm_cons (scm_from_locale_string (c_name), result);
3181 c_index++;
3182 }
3183 }
3184 while (!err);
3185
3186 if (EXPECT_FALSE (err != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE))
3187 scm_gnutls_error (err, FUNC_NAME);
3188
3189 return (scm_reverse_x (result, SCM_EOL));
3190 }
3191
3192 #undef FUNC_NAME
3193
3194 SCM_DEFINE (scm_gnutls_openpgp_certificate_algorithm,
3195 "%openpgp-certificate-algorithm",
3196 1, 0, 0,
3197 (SCM key),
3198 "Return two values: the certificate algorithm used by "
3199 "@var{key} and the number of bits used.")
3200 #define FUNC_NAME s_scm_gnutls_openpgp_certificate_algorithm
3201 {
3202 gnutls_openpgp_crt_t c_key;
3203 unsigned int c_bits;
3204 gnutls_pk_algorithm_t c_algo;
3205
3206 c_key = scm_to_gnutls_openpgp_certificate (key, 1, FUNC_NAME);
3207 c_algo = gnutls_openpgp_crt_get_pk_algorithm (c_key, &c_bits);
3208
3209 return (scm_values (scm_list_2 (scm_from_gnutls_pk_algorithm (c_algo),
3210 scm_from_uint (c_bits))));
3211 }
3212
3213 #undef FUNC_NAME
3214
3215 SCM_DEFINE (scm_gnutls_openpgp_certificate_version,
3216 "%openpgp-certificate-version",
3217 1, 0, 0,
3218 (SCM key),
3219 "Return the version of the OpenPGP message format (RFC2440) "
3220 "honored by @var{key}.")
3221 #define FUNC_NAME s_scm_gnutls_openpgp_certificate_version
3222 {
3223 int c_version;
3224 gnutls_openpgp_crt_t c_key;
3225
3226 c_key = scm_to_gnutls_openpgp_certificate (key, 1, FUNC_NAME);
3227 c_version = gnutls_openpgp_crt_get_version (c_key);
3228
3229 return (scm_from_int (c_version));
3230 }
3231
3232 #undef FUNC_NAME
3233
3234 SCM_DEFINE (scm_gnutls_openpgp_certificate_usage, "%openpgp-certificate-usage",
3235 1, 0, 0,
3236 (SCM key),
3237 "Return a list of values denoting the key usage of @var{key}.")
3238 #define FUNC_NAME s_scm_gnutls_openpgp_certificate_usage
3239 {
3240 int err;
3241 unsigned int c_usage = 0;
3242 gnutls_openpgp_crt_t c_key;
3243
3244 c_key = scm_to_gnutls_openpgp_certificate (key, 1, FUNC_NAME);
3245
3246 err = gnutls_openpgp_crt_get_key_usage (c_key, &c_usage);
3247 if (EXPECT_FALSE (err))
3248 scm_gnutls_error (err, FUNC_NAME);
3249
3250 return (scm_from_gnutls_key_usage_flags (c_usage));
3251 }
3252
3253 #undef FUNC_NAME
3254
3255
3256
3257 /* OpenPGP keyrings. */
3258
3259 SCM_DEFINE (scm_gnutls_import_openpgp_keyring, "import-openpgp-keyring",
3260 2, 0, 0,
3261 (SCM data, SCM format),
3262 "Import @var{data} (a u8vector) according to @var{format} "
3263 "and return the imported keyring.")
3264 #define FUNC_NAME s_scm_gnutls_import_openpgp_keyring
3265 {
3266 int err;
3267 gnutls_openpgp_keyring_t c_keyring;
3268 gnutls_openpgp_crt_fmt_t c_format;
3269 gnutls_datum_t c_data_d;
3270 scm_t_array_handle c_data_handle;
3271 const char *c_data;
3272 size_t c_data_len;
3273
3274 SCM_VALIDATE_ARRAY (1, data);
3275 c_format = scm_to_gnutls_openpgp_certificate_format (format, 2, FUNC_NAME);
3276
3277 c_data = scm_gnutls_get_array (data, &c_data_handle, &c_data_len,
3278 FUNC_NAME);
3279
3280 c_data_d.data = (unsigned char *) c_data;
3281 c_data_d.size = c_data_len;
3282
3283 err = gnutls_openpgp_keyring_init (&c_keyring);
3284 if (EXPECT_FALSE (err))
3285 {
3286 scm_gnutls_release_array (&c_data_handle);
3287 scm_gnutls_error (err, FUNC_NAME);
3288 }
3289
3290 err = gnutls_openpgp_keyring_import (c_keyring, &c_data_d, c_format);
3291 scm_gnutls_release_array (&c_data_handle);
3292
3293 if (EXPECT_FALSE (err))
3294 {
3295 gnutls_openpgp_keyring_deinit (c_keyring);
3296 scm_gnutls_error (err, FUNC_NAME);
3297 }
3298
3299 return (scm_from_gnutls_openpgp_keyring (c_keyring));
3300 }
3301
3302 #undef FUNC_NAME
3303
3304 SCM_DEFINE (scm_gnutls_openpgp_keyring_contains_key_id_p,
3305 "%openpgp-keyring-contains-key-id?",
3306 2, 0, 0,
3307 (SCM keyring, SCM id),
3308 "Return @code{#f} if key ID @var{id} is in @var{keyring}, "
3309 "@code{#f} otherwise.")
3310 #define FUNC_NAME s_scm_gnutls_openpgp_keyring_contains_key_id_p
3311 {
3312 int c_result;
3313 gnutls_openpgp_keyring_t c_keyring;
3314 scm_t_array_handle c_id_handle;
3315 const char *c_id;
3316 size_t c_id_len;
3317
3318 c_keyring = scm_to_gnutls_openpgp_keyring (keyring, 1, FUNC_NAME);
3319 SCM_VALIDATE_ARRAY (1, id);
3320
3321 c_id = scm_gnutls_get_array (id, &c_id_handle, &c_id_len, FUNC_NAME);
3322 if (EXPECT_FALSE (c_id_len != 8))
3323 {
3324 scm_gnutls_release_array (&c_id_handle);
3325 scm_wrong_type_arg (FUNC_NAME, 1, id);
3326 }
3327
3328 c_result = gnutls_openpgp_keyring_check_id (c_keyring,
3329 (unsigned char *) c_id,
3330 0 /* unused */ );
3331
3332 scm_gnutls_release_array (&c_id_handle);
3333
3334 return (scm_from_bool (c_result == 0));
3335 }
3336
3337 #undef FUNC_NAME
3338
3339
3340 /* OpenPGP certificates. */
3341
3342 SCM_DEFINE (scm_gnutls_set_certificate_credentials_openpgp_keys_x,
3343 "%set-certificate-credentials-openpgp-keys!",
3344 3, 0, 0,
3345 (SCM cred, SCM pub, SCM sec),
3346 "Use certificate @var{pub} and secret key @var{sec} in "
3347 "certificate credentials @var{cred}.")
3348 #define FUNC_NAME s_scm_gnutls_set_certificate_credentials_openpgp_keys_x
3349 {
3350 int err;
3351 gnutls_certificate_credentials_t c_cred;
3352 gnutls_openpgp_crt_t c_pub;
3353 gnutls_openpgp_privkey_t c_sec;
3354
3355 c_cred = scm_to_gnutls_certificate_credentials (cred, 1, FUNC_NAME);
3356 c_pub = scm_to_gnutls_openpgp_certificate (pub, 2, FUNC_NAME);
3357 c_sec = scm_to_gnutls_openpgp_private_key (sec, 3, FUNC_NAME);
3358
3359 err = gnutls_certificate_set_openpgp_key (c_cred, c_pub, c_sec);
3360 if (EXPECT_FALSE (err))
3361 scm_gnutls_error (err, FUNC_NAME);
3362
3363 return SCM_UNSPECIFIED;
3364 }
3365
3366 #undef FUNC_NAME
3367
3368
3369
3370 /* Debugging. */
3371
3372 static SCM log_procedure = SCM_BOOL_F;
3373
3374 static void
scm_gnutls_log(int level,const char * str)3375 scm_gnutls_log (int level, const char *str)
3376 {
3377 if (scm_is_true (log_procedure))
3378 (void) scm_call_2 (log_procedure, scm_from_int (level),
3379 scm_from_locale_string (str));
3380 }
3381
3382 SCM_DEFINE (scm_gnutls_set_log_procedure_x, "set-log-procedure!",
3383 1, 0, 0,
3384 (SCM proc),
3385 "Use @var{proc} (a two-argument procedure) as the global "
3386 "GnuTLS log procedure.")
3387 #define FUNC_NAME s_scm_gnutls_set_log_procedure_x
3388 {
3389 SCM_VALIDATE_PROC (1, proc);
3390
3391 if (scm_is_true (log_procedure))
3392 (void) scm_gc_unprotect_object (log_procedure);
3393
3394 log_procedure = scm_gc_protect_object (proc);
3395 gnutls_global_set_log_function (scm_gnutls_log);
3396
3397 return SCM_UNSPECIFIED;
3398 }
3399
3400 #undef FUNC_NAME
3401
3402 SCM_DEFINE (scm_gnutls_set_log_level_x, "set-log-level!", 1, 0, 0,
3403 (SCM level),
3404 "Enable GnuTLS logging up to @var{level} (an integer).")
3405 #define FUNC_NAME s_scm_gnutls_set_log_level_x
3406 {
3407 unsigned int c_level;
3408
3409 c_level = scm_to_uint (level);
3410 gnutls_global_set_log_level (c_level);
3411
3412 return SCM_UNSPECIFIED;
3413 }
3414
3415 #undef FUNC_NAME
3416
3417
3418 /* Initialization. */
3419
3420 void
scm_init_gnutls(void)3421 scm_init_gnutls (void)
3422 {
3423 #include "core.x"
3424
3425 /* Use Guile's allocation routines, which will run the GC if need be. */
3426 (void) gnutls_global_init ();
3427
3428 scm_gnutls_define_enums ();
3429
3430 scm_init_gnutls_error ();
3431
3432 scm_init_gnutls_session_record_port_type ();
3433
3434 weak_refs = scm_make_weak_key_hash_table (scm_from_int (42));
3435 weak_refs = scm_permanent_object (weak_refs);
3436 }
3437