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