1 ;;; GnuTLS --- Guile bindings for GnuTLS.
2 ;;; Copyright (C) 2007, 2010 Free Software Foundation, Inc.
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.
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.
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
18 ;;; Written by Ludovic Courtès <ludo@chbouib.org>
20 (define-module (gnutls build enums)
21 :use-module (srfi srfi-1)
22 :use-module (srfi srfi-9)
23 :use-module (gnutls build utils)
25 :export (make-enum-type enum-type-subsystem enum-type-value-alist
26 enum-type-c-type enum-type-get-name-function
27 enum-type-automatic-get-name-function
29 enum-type-to-c-function enum-type-from-c-function
31 output-enum-smob-definitions output-enum-definitions
32 output-enum-declarations
33 output-enum-definition-function output-c->enum-converter
34 output-enum->c-converter
36 %cipher-enum %mac-enum %compression-method-enum %kx-enum
37 %protocol-enum %certificate-type-enum
39 %gnutls-enums %gnutls-extra-enums))
42 ;;; This module helps with the creation of bindings for the C enumerate
43 ;;; types. It aims at providing strong typing (i.e., one cannot use an
44 ;;; enumerate value of the wrong type) along with authenticity checks (i.e.,
45 ;;; values of a given enumerate type cannot be forged---for instance, one
46 ;;; cannot use some random integer as an enumerate value). Additionally,
47 ;;; Scheme enums representing the same C enum value should be `eq?'.
49 ;;; To that end, Scheme->C conversions are optimized (a simple
50 ;;; `SCM_SMOB_DATA'), since that is the most common usage pattern.
51 ;;; Conversely, C->Scheme conversions take time proportional to the number of
52 ;;; value in the enum type.
57 ;;; Enumeration tools.
60 (define-record-type <enum-type>
61 (%make-enum-type subsystem c-type enum-map get-name value-prefix)
63 (subsystem enum-type-subsystem)
64 (enum-map enum-type-value-alist)
65 (c-type enum-type-c-type)
66 (get-name enum-type-get-name-function)
67 (value-prefix enum-type-value-prefix))
70 (define (make-enum-type subsystem c-type values get-name . value-prefix)
71 ;; Return a new enumeration type.
72 (let ((value-prefix (if (null? value-prefix)
75 (%make-enum-type subsystem c-type
76 (make-enum-map subsystem values value-prefix)
77 get-name value-prefix)))
80 (define (make-enum-map subsystem values value-prefix)
81 ;; Return an alist mapping C enum values (strings) to Scheme symbols.
82 (define (value-symbol->string value)
83 (string-upcase (scheme-symbol->c-name value)))
85 (define (make-c-name value)
88 ;; automatically derive the C value name.
89 (string-append "GNUTLS_" (string-upcase (symbol->string subsystem))
90 "_" (value-symbol->string value)))
92 (string-append value-prefix (value-symbol->string value)))))
95 (cons (make-c-name value) value))
98 (define (enum-type-smob-name enum)
99 ;; Return the C name of the smob type for ENUM.
100 (string-append "scm_tc16_gnutls_"
101 (scheme-symbol->c-name (enum-type-subsystem enum))
104 (define (enum-type-smob-list enum)
105 ;; Return the name of the C variable holding a list of value (SMOBs) for
106 ;; ENUM. This list is used when converting from C to Scheme.
107 (string-append "scm_gnutls_"
108 (scheme-symbol->c-name (enum-type-subsystem enum))
111 (define (enum-type-to-c-function enum)
112 ;; Return the name of the C `scm_to_' function for ENUM.
113 (string-append "scm_to_gnutls_"
114 (scheme-symbol->c-name (enum-type-subsystem enum))))
116 (define (enum-type-from-c-function enum)
117 ;; Return the name of the C `scm_from_' function for ENUM.
118 (string-append "scm_from_gnutls_"
119 (scheme-symbol->c-name (enum-type-subsystem enum))))
121 (define (enum-type-automatic-get-name-function enum)
122 ;; Return the name of an automatically-generated C function that returns a
123 ;; string describing the given enum value of type ENUM.
124 (string-append "scm_gnutls_"
125 (scheme-symbol->c-name (enum-type-subsystem enum))
130 ;;; C code generation.
133 (define (output-enum-smob-definitions enum port)
134 (let ((smob (enum-type-smob-name enum))
135 (get-name (enum-type-get-name-function enum)))
136 (format port "SCM_GLOBAL_SMOB (~a, \"~a\", 0);~%"
137 smob (enum-type-subsystem enum))
138 (format port "SCM ~a = SCM_EOL;~%"
139 (enum-type-smob-list enum))
141 (if (not (string? get-name))
142 ;; Generate a "get name" function.
143 (output-enum-get-name-function enum port))
145 ;; Generate the printer and `->string' function.
146 (let ((get-name (or get-name
147 (enum-type-automatic-get-name-function enum))))
148 (let ((subsystem (scheme-symbol->c-name (enum-type-subsystem enum))))
150 (format port "SCM_SMOB_PRINT (~a, ~a_print, obj, port, pstate)~%{~%"
152 (format port " scm_puts (\"#<gnutls-~a-enum \", port);~%"
153 (enum-type-subsystem enum))
154 (format port " scm_puts (~a (~a (obj, 1, \"~a_print\")), port);~%"
155 get-name (enum-type-to-c-function enum) subsystem)
156 (format port " scm_puts (\">\", port);~%")
157 (format port " return 1;~%")
161 (format port "SCM_DEFINE (scm_gnutls_~a_to_string, \"~a->string\", "
162 subsystem (enum-type-subsystem enum))
163 (format port "1, 0, 0,~%")
164 (format port " (SCM enumval),~%")
165 (format port " \"Return a string describing ")
166 (format port "@var{enumval}, a @code{~a} value.\")~%"
167 (enum-type-subsystem enum))
168 (format port "#define FUNC_NAME s_scm_gnutls_~a_to_string~%"
171 (format port " ~a c_enum;~%"
172 (enum-type-c-type enum))
173 (format port " const char *c_string;~%")
174 (format port " c_enum = ~a (enumval, 1, FUNC_NAME);~%"
175 (enum-type-to-c-function enum))
176 (format port " c_string = ~a (c_enum);~%"
178 (format port " return (scm_from_locale_string (c_string));~%")
180 (format port "#undef FUNC_NAME~%")))))
182 (define (output-enum-definitions enum port)
183 ;; Output to PORT the Guile C code that defines the values of ENUM-ALIST.
184 (let ((subsystem (scheme-symbol->c-name (enum-type-subsystem enum))))
185 (format port " enum_values = SCM_EOL;~%")
186 (for-each (lambda (c+scheme)
187 (format port " SCM_NEWSMOB (enum_smob, ~a, "
188 (enum-type-smob-name enum))
189 (format port "(scm_t_bits) ~a);~%"
191 (format port " enum_values = scm_cons (enum_smob, ")
192 (format port "enum_values);~%")
193 (format port " scm_c_define (\"~a\", enum_smob);~%"
194 (symbol-append (enum-type-subsystem enum) '/
196 (enum-type-value-alist enum))
197 (format port " ~a = scm_permanent_object (enum_values);~%"
198 (enum-type-smob-list enum))))
200 (define (output-enum-declarations enum port)
201 ;; Issue header file declarations needed for the inline functions that
202 ;; handle ENUM values.
203 (format port "SCM_API scm_t_bits ~a;~%"
204 (enum-type-smob-name enum))
205 (format port "SCM_API SCM ~a;~%"
206 (enum-type-smob-list enum)))
208 (define (output-enum-definition-function enums port)
209 ;; Output a C function that does all the `scm_c_define ()' for the enums
211 (format port "static inline void~%scm_gnutls_define_enums (void)~%{~%")
212 (format port " SCM enum_values, enum_smob;~%")
213 (for-each (lambda (enum)
214 (output-enum-definitions enum port))
218 (define (output-c->enum-converter enum port)
219 ;; Output a C->Scheme converted for ENUM. This works by walking the list
220 ;; of available enum values (SMOBs) for ENUM and then returning the
221 ;; matching SMOB, so that users can then compare enums using `eq?'. While
222 ;; this may look inefficient, this shouldn't be a problem since (i)
223 ;; conversion in that direction is rarely needed and (ii) the number of
224 ;; values per enum is expected to be small.
225 (format port "static inline SCM~%~a (~a c_obj)~%{~%"
226 (enum-type-from-c-function enum)
227 (enum-type-c-type enum))
228 (format port " SCM pair, result = SCM_BOOL_F;~%")
229 (format port " for (pair = ~a; scm_is_pair (pair); "
230 (enum-type-smob-list enum))
231 (format port "pair = SCM_CDR (pair))~%")
233 (format port " SCM enum_smob;~%")
234 (format port " enum_smob = SCM_CAR (pair);~%")
235 (format port " if ((~a) SCM_SMOB_DATA (enum_smob) == c_obj)~%"
236 (enum-type-c-type enum))
238 (format port " result = enum_smob;~%")
239 (format port " break;~%")
242 (format port " return result;~%")
245 (define (output-enum->c-converter enum port)
246 (let* ((c-type-name (enum-type-c-type enum))
247 (subsystem (scheme-symbol->c-name (enum-type-subsystem enum))))
250 "static inline ~a~%~a (SCM obj, unsigned pos, const char *func)~%"
251 c-type-name (enum-type-to-c-function enum))
252 (format port "#define FUNC_NAME func~%")
254 (format port " SCM_VALIDATE_SMOB (pos, obj, ~a);~%"
255 (string-append "gnutls_" subsystem "_enum"))
256 (format port " return ((~a) SCM_SMOB_DATA (obj));~%"
259 (format port "#undef FUNC_NAME~%")))
261 (define (output-enum-get-name-function enum port)
262 ;; Output a C function that, when passed a C ENUM value, returns a C string
263 ;; representing that value.
264 (let ((function (enum-type-automatic-get-name-function enum)))
266 "static const char *~%~a (~a c_obj)~%"
267 function (enum-type-c-type enum))
269 (format port " static const struct ")
270 (format port "{ ~a value; const char *name; } "
271 (enum-type-c-type enum))
272 (format port "table[] =~%")
274 (for-each (lambda (c+scheme)
275 (format port " { ~a, \"~a\" },~%"
276 (car c+scheme) (cdr c+scheme)))
277 (enum-type-value-alist enum))
278 (format port " };~%")
279 (format port " unsigned i;~%")
280 (format port " const char *name = NULL;~%")
281 (format port " for (i = 0; i < ~a; i++)~%"
282 (length (enum-type-value-alist enum)))
284 (format port " if (table[i].value == c_obj)~%")
286 (format port " name = table[i].name;~%")
287 (format port " break;~%")
290 (format port " return (name);~%")
291 (format port "}~%")))
295 ;;; Actual enumerations.
299 (make-enum-type 'cipher "gnutls_cipher_algorithm_t"
300 '(null arcfour 3des-cbc aes-128-cbc aes-256-cbc
301 arcfour-40 rc2-40-cbc des-cbc)
302 "gnutls_cipher_get_name"))
305 (make-enum-type 'kx "gnutls_kx_algorithm_t"
306 '(rsa dhe-dss dhe-rsa anon-dh srp rsa-export
307 srp-rsa srp-dss psk dhe-dss)
308 "gnutls_kx_get_name"))
311 (make-enum-type 'params "gnutls_params_type_t"
315 (define %credentials-enum
316 (make-enum-type 'credentials "gnutls_credentials_type_t"
317 '(certificate anon srp psk ia)
322 (make-enum-type 'mac "gnutls_mac_algorithm_t"
323 '(unknown null md5 sha1 rmd160 md2)
324 "gnutls_mac_get_name"))
327 (make-enum-type 'digest "gnutls_digest_algorithm_t"
328 '(null md5 sha1 rmd160 md2)
332 (define %compression-method-enum
333 (make-enum-type 'compression-method "gnutls_compression_method_t"
335 "gnutls_compression_get_name"
338 (define %connection-end-enum
339 (make-enum-type 'connection-end "gnutls_connection_end_t"
344 (define %alert-level-enum
345 (make-enum-type 'alert-level "gnutls_alert_level_t"
350 (define %alert-description-enum
351 (make-enum-type 'alert-description "gnutls_alert_description_t"
352 '(close-notify unexpected-message bad-record-mac
353 decryption-failed record-overflow decompression-failure handshake-failure
354 ssl3-no-certificate bad-certificate unsupported-certificate
355 certificate-revoked certificate-expired certificate-unknown illegal-parameter
356 unknown-ca access-denied decode-error decrypt-error export-restriction
357 protocol-version insufficient-security internal-error user-canceled
358 no-renegotiation unsupported-extension certificate-unobtainable
359 unrecognized-name unknown-psk-identity
360 inner-application-failure inner-application-verification)
364 (define %handshake-description-enum
365 (make-enum-type 'handshake-description "gnutls_handshake_description_t"
366 '(hello-request client-hello server-hello certificate-pkt
367 server-key-exchange certificate-request server-hello-done
368 certificate-verify client-key-exchange finished)
370 "GNUTLS_HANDSHAKE_"))
372 (define %certificate-status-enum
373 (make-enum-type 'certificate-status "gnutls_certificate_status_t"
374 '(invalid revoked signer-not-found signer-not-ca
379 (define %certificate-request-enum
380 (make-enum-type 'certificate-request "gnutls_certificate_request_t"
381 '(ignore request require)
385 ;; XXX: Broken naming convention.
386 ; (define %openpgp-key-status-enum
387 ; (make-enum-type 'openpgp-key-status "gnutls_openpgp_key_status_t"
390 ; "GNUTLS_OPENPGP_"))
392 (define %close-request-enum
393 (make-enum-type 'close-request "gnutls_close_request_t"
394 '(rdwr wr) ;; FIXME: Check the meaning and rename
398 (define %protocol-enum
399 (make-enum-type 'protocol "gnutls_protocol_t"
400 '(ssl3 tls1-0 tls1-1 version-unknown)
404 (define %certificate-type-enum
405 (make-enum-type 'certificate-type "gnutls_certificate_type_t"
407 "gnutls_certificate_type_get_name"
410 (define %x509-certificate-format-enum
411 (make-enum-type 'x509-certificate-format "gnutls_x509_crt_fmt_t"
416 (define %x509-subject-alternative-name-enum
417 (make-enum-type 'x509-subject-alternative-name
418 "gnutls_x509_subject_alt_name_t"
419 '(dnsname rfc822name uri ipaddress)
423 (define %pk-algorithm-enum
424 (make-enum-type 'pk-algorithm "gnutls_pk_algorithm_t"
426 "gnutls_pk_algorithm_get_name"
429 (define %sign-algorithm-enum
430 (make-enum-type 'sign-algorithm "gnutls_sign_algorithm_t"
431 '(unknown rsa-sha1 dsa-sha1 rsa-md5 rsa-md2
433 "gnutls_sign_algorithm_get_name"
436 (define %psk-key-format-enum
437 (make-enum-type 'psk-key-format "gnutls_psk_key_flags"
442 (define %key-usage-enum
443 ;; Not actually an enum on the C side.
444 (make-enum-type 'key-usage "int"
445 '(digital-signature non-repudiation key-encipherment
446 data-encipherment key-agreement key-cert-sign
447 crl-sign encipher-only decipher-only)
451 (define %certificate-verify-enum
452 (make-enum-type 'certificate-verify "gnutls_certificate_verify_flags"
453 '(disable-ca-sign allow-x509-v1-ca-crt
454 do-not-allow-same allow-any-x509-v1-ca-crt
455 allow-sign-rsa-md2 allow-sign-rsa-md5)
460 (make-enum-type 'error "int"
463 unknown-compression-algorithm
466 unsupported-version-packet
467 unexpected-packet-length
471 warning-alert-received
472 error-in-finished-packet
473 unexpected-handshake-packet
485 insufficient-credentials
486 insuficient-credentials
490 base64-decoding-error
499 x509-unsupported-critical-extension
507 received-illegal-parameter
508 requested-data-not-available
510 received-illegal-extension
512 dh-prime-unacceptable
514 too-many-empty-packets
517 library-version-mismatch
518 no-temporary-rsa-params
520 no-compression-algorithms
522 openpgp-getkey-failed
525 srp-pwd-parsing-error
526 no-temporary-dh-params
527 asn1-element-not-found
528 asn1-identifier-not-found
540 x509-certificate-error
541 certificate-key-mismatch
542 unsupported-certificate-type
544 openpgp-fingerprint-unsupported
545 x509-unsupported-attribute
547 unknown-hash-algorithm
548 unknown-pkcs-content-type
549 unknown-pkcs-bag-type
553 warning-ia-iphf-received
554 warning-ia-fphf-received
556 base64-encoding-error
557 incompatible-gcrypt-library
558 incompatible-crypto-library
559 incompatible-libtasn1-library
560 openpgp-keyring-error
563 unimplemented-feature)
568 (define %openpgp-certificate-format-enum
569 (make-enum-type 'openpgp-certificate-format "gnutls_openpgp_crt_fmt_t"
572 "GNUTLS_OPENPGP_FMT_"))
575 (define %gnutls-enums
577 (list %cipher-enum %kx-enum %params-enum %credentials-enum %mac-enum
578 %digest-enum %compression-method-enum %connection-end-enum
579 %alert-level-enum %alert-description-enum %handshake-description-enum
580 %certificate-status-enum %certificate-request-enum
581 %close-request-enum %protocol-enum %certificate-type-enum
582 %x509-certificate-format-enum %x509-subject-alternative-name-enum
583 %pk-algorithm-enum %sign-algorithm-enum
584 %psk-key-format-enum %key-usage-enum %certificate-verify-enum
587 (define %gnutls-extra-enums
588 ;; All enums for GnuTLS-extra (GPL).
589 (list %openpgp-certificate-format-enum))
596 ;;; arch-tag: 9e3eb6bb-61a5-4e85-861f-1914ab9677b0