1 ;;; GNU Guix --- Functional package management for GNU
2 ;;; Copyright © 2013, 2014, 2015, 2017 Ludovic Courtès <ludo@gnu.org>
4 ;;; This file is part of GNU Guix.
6 ;;; GNU Guix is free software; you can redistribute it and/or modify it
7 ;;; under the terms of the GNU General Public License as published by
8 ;;; the Free Software Foundation; either version 3 of the License, or (at
9 ;;; your option) any later version.
11 ;;; GNU Guix is distributed in the hope that it will be useful, but
12 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
13 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ;;; GNU General Public License for more details.
16 ;;; You should have received a copy of the GNU General Public License
17 ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
19 (define-module (guix pk-crypto)
20 #:use-module (guix base16)
21 #:use-module (guix gcrypt)
23 #:use-module (system foreign)
24 #:use-module (rnrs bytevectors)
25 #:use-module (ice-9 match)
26 #:use-module (ice-9 rdelim)
27 #:export (canonical-sexp?
30 string->canonical-sexp
31 canonical-sexp->string
33 number->canonical-sexp
37 canonical-sexp-nth-data
50 #:re-export (gcrypt-version))
55 ;;; Public key cryptographic routines from GNU Libgcrypt.
57 ;;; Libgcrypt uses "canonical s-expressions" to represent key material,
58 ;;; parameters, and data. We keep it as an opaque object to map them to
59 ;;; Scheme s-expressions because (1) Libgcrypt sexps may be stored in secure
60 ;;; memory, and (2) the read syntax is different.
62 ;;; A 'canonical-sexp->sexp' procedure is provided nevertheless, for use in
63 ;;; cases where it is safe to move data out of Libgcrypt---e.g., when
64 ;;; processing ACL entries, public keys, etc.
66 ;;; Canonical sexps were defined by Rivest et al. in the IETF draft at
67 ;;; <http://people.csail.mit.edu/rivest/Sexp.txt> for the purposes of SPKI
68 ;;; (see <http://www.ietf.org/rfc/rfc2693.txt>.)
72 ;; Libgcrypt "s-expressions".
73 (define-wrapped-pointer-type <canonical-sexp>
75 naked-pointer->canonical-sexp
76 canonical-sexp->pointer
78 ;; Don't print OBJ's external representation: we don't want key material
79 ;; to leak in backtraces and such.
80 (format port "#<canonical-sexp ~a | ~a>"
81 (number->string (object-address obj) 16)
82 (number->string (pointer-address (canonical-sexp->pointer obj))
85 (define finalize-canonical-sexp!
86 (libgcrypt-func "gcry_sexp_release"))
88 (define-inlinable (pointer->canonical-sexp ptr)
89 "Return a <canonical-sexp> that wraps PTR."
90 (let* ((sexp (naked-pointer->canonical-sexp ptr))
91 (ptr* (canonical-sexp->pointer sexp)))
92 ;; Did we already have a <canonical-sexp> object for PTR?
93 (when (equal? ptr ptr*)
94 ;; No, so we can safely add a finalizer (in Guile 2.0.9
95 ;; 'set-pointer-finalizer!' *adds* a finalizer rather than replacing the
97 (set-pointer-finalizer! ptr finalize-canonical-sexp!))
101 (let* ((ptr (libgcrypt-func "gcry_strsource"))
102 (proc (pointer->procedure '* ptr (list int))))
104 "Return the error source (a string) for ERR, an error code as thrown
105 along with 'gcry-error'."
106 (pointer->string (proc err)))))
109 (let* ((ptr (libgcrypt-func "gcry_strerror"))
110 (proc (pointer->procedure '* ptr (list int))))
112 "Return the error description (a string) for ERR, an error code as
113 thrown along with 'gcry-error'."
114 (pointer->string (proc err)))))
116 (define string->canonical-sexp
117 (let* ((ptr (libgcrypt-func "gcry_sexp_new"))
118 (proc (pointer->procedure int ptr `(* * ,size_t ,int))))
120 "Parse STR and return the corresponding gcrypt s-expression."
122 ;; When STR comes from 'canonical-sexp->string', it may contain
123 ;; characters that are really meant to be interpreted as bytes as in a C
124 ;; 'char *'. Thus, convert STR to ISO-8859-1 so the byte values of the
125 ;; characters are preserved.
126 (let* ((sexp (bytevector->pointer (make-bytevector (sizeof '*))))
127 (err (proc sexp (string->pointer str "ISO-8859-1") 0 1)))
129 (pointer->canonical-sexp (dereference-pointer sexp))
130 (throw 'gcry-error 'string->canonical-sexp err))))))
132 (define-syntax GCRYSEXP_FMT_ADVANCED
133 (identifier-syntax 3))
135 (define canonical-sexp->string
136 (let* ((ptr (libgcrypt-func "gcry_sexp_sprint"))
137 (proc (pointer->procedure size_t ptr `(* ,int * ,size_t))))
139 "Return a textual representation of SEXP."
140 (let loop ((len 1024))
141 (let* ((buf (bytevector->pointer (make-bytevector len)))
142 (size (proc (canonical-sexp->pointer sexp)
143 GCRYSEXP_FMT_ADVANCED buf len)))
146 (pointer->string buf size "ISO-8859-1")))))))
148 (define (read-file-sexp file)
149 "Return the canonical sexp read from FILE."
150 (call-with-input-file file
151 (compose string->canonical-sexp
154 (define canonical-sexp-car
155 (let* ((ptr (libgcrypt-func "gcry_sexp_car"))
156 (proc (pointer->procedure '* ptr '(*))))
158 "Return the first element of LST, an sexp, if that element is a list;
159 return #f if LST or its first element is not a list (this is different from
160 the usual Lisp 'car'.)"
161 (let ((result (proc (canonical-sexp->pointer lst))))
162 (if (null-pointer? result)
164 (pointer->canonical-sexp result))))))
166 (define canonical-sexp-cdr
167 (let* ((ptr (libgcrypt-func "gcry_sexp_cdr"))
168 (proc (pointer->procedure '* ptr '(*))))
170 "Return the tail of LST, an sexp, or #f if LST is not a list."
171 (let ((result (proc (canonical-sexp->pointer lst))))
172 (if (null-pointer? result)
174 (pointer->canonical-sexp result))))))
176 (define canonical-sexp-nth
177 (let* ((ptr (libgcrypt-func "gcry_sexp_nth"))
178 (proc (pointer->procedure '* ptr `(* ,int))))
180 "Return the INDEXth nested element of LST, an s-expression. Return #f
181 if that element does not exist, or if it's an atom. (Note: this is obviously
182 different from Scheme's 'list-ref'.)"
183 (let ((result (proc (canonical-sexp->pointer lst) index)))
184 (if (null-pointer? result)
186 (pointer->canonical-sexp result))))))
188 (define (dereference-size_t p)
189 "Return the size_t value pointed to by P."
190 (bytevector-uint-ref (pointer->bytevector p (sizeof size_t))
191 0 (native-endianness)
194 (define canonical-sexp-length
195 (let* ((ptr (libgcrypt-func "gcry_sexp_length"))
196 (proc (pointer->procedure int ptr '(*))))
198 "Return the length of SEXP if it's a list (including the empty list);
199 return zero if SEXP is an atom."
200 (proc (canonical-sexp->pointer sexp)))))
202 (define token-string?
203 (let ((token-cs (char-set-union char-set:digit
205 (char-set #\- #\. #\/ #\_
208 "Return #t if STR is a token as per Section 4.3 of
209 <http://people.csail.mit.edu/rivest/Sexp.txt>."
210 (and (not (string-null? str))
211 (string-every token-cs str)
212 (not (char-set-contains? char-set:digit (string-ref str 0)))))))
214 (define canonical-sexp-nth-data
215 (let* ((ptr (libgcrypt-func "gcry_sexp_nth_data"))
216 (proc (pointer->procedure '* ptr `(* ,int *))))
218 "Return as a symbol (for \"sexp tokens\") or a bytevector (for any other
219 \"octet string\") the INDEXth data element (atom) of LST, an s-expression.
220 Return #f if that element does not exist, or if it's a list."
221 (let* ((size* (bytevector->pointer (make-bytevector (sizeof '*))))
222 (result (proc (canonical-sexp->pointer lst) index size*)))
223 (if (null-pointer? result)
225 (let* ((len (dereference-size_t size*))
226 (str (pointer->string result len "ISO-8859-1")))
227 ;; The sexp spec speaks of "tokens" and "octet strings".
228 ;; Sometimes these octet strings are actual strings (text),
229 ;; sometimes they're bytevectors, and sometimes they're
230 ;; multi-precision integers (MPIs). Only the application knows.
231 ;; However, for convenience, we return a symbol when a token is
232 ;; encountered since tokens are frequent (at least in the 'car'
234 (if (token-string? str)
235 (string->symbol str) ; an sexp "token"
236 (bytevector-copy ; application data, textual or binary
237 (pointer->bytevector result len)))))))))
239 (define (number->canonical-sexp number)
240 "Return an s-expression representing NUMBER."
241 (string->canonical-sexp (string-append "#" (number->string number 16) "#")))
243 (define* (bytevector->hash-data bv
246 #:key (key-type 'ecc))
247 "Given BV, a bytevector containing a hash of type HASH-ALGO, return an
248 s-expression suitable for use as the 'data' argument for 'sign'. KEY-TYPE
249 must be a symbol: 'dsa, 'ecc, or 'rsa."
250 (string->canonical-sexp
251 (format #f "(data (flags ~a) (hash \"~a\" #~a#))"
253 ((ecc dsa) "rfc6979")
255 (else (error "unknown key type" key-type)))
257 (bytevector->base16-string bv))))
259 (define (key-type sexp)
260 "Return a symbol denoting the type of public or private key represented by
261 SEXP--e.g., 'rsa', 'ecc'--or #f if SEXP does not denote a valid key."
262 (case (canonical-sexp-nth-data sexp 0)
263 ((public-key private-key)
264 (canonical-sexp-nth-data (canonical-sexp-nth sexp 1) 0))
267 (define* (hash-data->bytevector data)
268 "Return two values: the hash value (a bytevector), and the hash algorithm (a
269 string) extracted from DATA, an sexp as returned by 'bytevector->hash-data'.
270 Return #f if DATA does not conform."
271 (let ((hash (find-sexp-token data 'hash)))
273 (let ((algo (canonical-sexp-nth-data hash 1))
274 (value (canonical-sexp-nth-data hash 2)))
275 (values value (symbol->string algo)))
279 (let* ((ptr (libgcrypt-func "gcry_pk_sign"))
280 (proc (pointer->procedure int ptr '(* * *))))
281 (lambda (data secret-key)
282 "Sign DATA, a canonical s-expression representing a suitable hash, with
283 SECRET-KEY (a canonical s-expression whose car is 'private-key'.) Note that
284 DATA must be a 'data' s-expression, as returned by
285 'bytevector->hash-data' (info \"(gcrypt) Cryptographic Functions\")."
286 (let* ((sig (bytevector->pointer (make-bytevector (sizeof '*))))
287 (err (proc sig (canonical-sexp->pointer data)
288 (canonical-sexp->pointer secret-key))))
290 (pointer->canonical-sexp (dereference-pointer sig))
291 (throw 'gcry-error 'sign err))))))
294 (let* ((ptr (libgcrypt-func "gcry_pk_verify"))
295 (proc (pointer->procedure int ptr '(* * *))))
296 (lambda (signature data public-key)
297 "Verify that SIGNATURE is a signature of DATA with PUBLIC-KEY, all of
298 which are gcrypt s-expressions."
299 (zero? (proc (canonical-sexp->pointer signature)
300 (canonical-sexp->pointer data)
301 (canonical-sexp->pointer public-key))))))
304 (let* ((ptr (libgcrypt-func "gcry_pk_genkey"))
305 (proc (pointer->procedure int ptr '(* *))))
307 "Return as an s-expression a new key pair for PARAMS. PARAMS must be an
308 s-expression like: (genkey (rsa (nbits 4:2048)))."
309 (let* ((key (bytevector->pointer (make-bytevector (sizeof '*))))
310 (err (proc key (canonical-sexp->pointer params))))
312 (pointer->canonical-sexp (dereference-pointer key))
313 (throw 'gcry-error 'generate-key err))))))
315 (define find-sexp-token
316 (let* ((ptr (libgcrypt-func "gcry_sexp_find_token"))
317 (proc (pointer->procedure '* ptr `(* * ,size_t))))
319 "Find in SEXP the first element whose 'car' is TOKEN and return it;
320 return #f if not found."
321 (let* ((token (string->pointer (symbol->string token)))
322 (res (proc (canonical-sexp->pointer sexp) token 0)))
323 (if (null-pointer? res)
325 (pointer->canonical-sexp res))))))
327 (define-inlinable (canonical-sexp-null? sexp)
328 "Return #t if SEXP is the empty-list sexp."
329 (null-pointer? (canonical-sexp->pointer sexp)))
331 (define (canonical-sexp-list? sexp)
332 "Return #t if SEXP is a list."
333 (or (canonical-sexp-null? sexp)
334 (> (canonical-sexp-length sexp) 0)))
336 (define (canonical-sexp-fold proc seed sexp)
337 "Fold PROC (as per SRFI-1) over SEXP, a canonical sexp."
338 (if (canonical-sexp-list? sexp)
339 (let ((len (canonical-sexp-length sexp)))
345 ;; XXX: Call 'nth-data' *before* 'nth' to work around
346 ;; <https://bugs.g10code.com/gnupg/issue1594>, which
347 ;; affects 1.6.0 and earlier versions.
348 (proc (or (canonical-sexp-nth-data sexp index)
349 (canonical-sexp-nth sexp index))
351 (error "sexp is not a list" sexp)))
353 (define (canonical-sexp->sexp sexp)
354 "Return a Scheme sexp corresponding to SEXP. This is particularly useful to
355 compare sexps (since Libgcrypt does not provide an 'equal?' procedure), or to
356 use pattern matching."
357 (if (canonical-sexp-list? sexp)
359 (canonical-sexp-fold (lambda (item result)
360 (cons (if (canonical-sexp? item)
361 (canonical-sexp->sexp item)
367 ;; As of Libgcrypt 1.6.0, there's no function to extract the buffer of a
368 ;; non-list sexp (!), so we first enlist SEXP, then get at its buffer.
369 (let ((sexp (string->canonical-sexp
370 (string-append "(" (canonical-sexp->string sexp)
372 (or (canonical-sexp-nth-data sexp 0)
373 (canonical-sexp-nth sexp 0)))))
375 (define (sexp->canonical-sexp sexp)
376 "Return a canonical sexp equivalent to SEXP, a Scheme sexp as returned by
377 'canonical-sexp->sexp'."
378 ;; XXX: This is inefficient, but the Libgcrypt API doesn't allow us to do
380 (string->canonical-sexp
381 (call-with-output-string
386 (for-each write item)
389 (format port " ~a" item))
392 (bytevector->base16-string item)))
394 (error "unsupported sexp item type" item))))
398 (define (gcrypt-error-printer port key args default-printer)
399 "Print the gcrypt error specified by ARGS."
402 (format port "In procedure ~a: ~a: ~a"
403 proc (error-source err) (error-string err)))))
405 (set-exception-printer! 'gcry-error gcrypt-error-printer)
407 ;;; pk-crypto.scm ends here