]> git.ozlabs.org Git - petitboot/blob - lib/security/gpg.c
lib: Add plugin_option type and protocol
[petitboot] / lib / security / gpg.c
1 /*
2  *  Copyright (C) 2016 Raptor Engineering, LLC
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; version 2 of the License.
7  *
8  *  This program is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *  GNU General Public License for more details.
12  *
13  *  You should have received a copy of the GNU General Public License
14  *  along with this program; if not, write to the Free Software
15  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  */
17
18 #if defined(HAVE_CONFIG_H)
19 #include "config.h"
20 #endif
21
22 #include <stdbool.h>
23 #include <stdlib.h>
24 #include <assert.h>
25 #include <dirent.h>
26 #include <string.h>
27 #include <fcntl.h>
28 #include <sys/types.h>
29
30 #include <log/log.h>
31 #include <file/file.h>
32 #include <talloc/talloc.h>
33 #include <url/url.h>
34 #include <util/util.h>
35 #include <i18n/i18n.h>
36
37 #include "gpg.h"
38
39 /*
40  * If --with-signed-boot is enabled lib/security provides the ability to handle
41  * gpg-signed and/or encrypted boot sources (kernel, initrd, etc).
42  * This can be used to enable a form of secure boot, but it is important to
43  * recognise that it depends on the security of the entire system, for example
44  * a full trusted-boot implementation. Petitboot can not and will not be able
45  * to guarantee secure boot by itself.
46  */
47
48 struct pb_url * gpg_get_signature_url(void *ctx, struct pb_url *base_file)
49 {
50         struct pb_url *signature_file = NULL;
51
52         signature_file = pb_url_copy(ctx, base_file);
53         talloc_free(signature_file->file);
54         signature_file->file = talloc_asprintf(signature_file,
55                 "%s.sig", base_file->file);
56         talloc_free(signature_file->path);
57         signature_file->path = talloc_asprintf(signature_file,
58                 "%s.sig", base_file->path);
59
60         return signature_file;
61 }
62
63 int decrypt_file(const char *filename,
64         FILE *authorized_signatures_handle, const char *keyring_path)
65 {
66         int result = 0;
67         int valid = 0;
68         size_t bytes_read = 0;
69         unsigned char buffer[8192];
70
71         if (filename == NULL)
72                 return -1;
73
74         gpgme_signature_t verification_signatures;
75         gpgme_verify_result_t verification_result;
76         gpgme_data_t ciphertext_data;
77         gpgme_data_t plaintext_data;
78         gpgme_engine_info_t enginfo;
79         gpgme_ctx_t gpg_context;
80         gpgme_error_t err;
81
82         /* Initialize gpgme */
83         setlocale (LC_ALL, "");
84         gpgme_check_version(NULL);
85         gpgme_set_locale(NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
86         err = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
87         if (err != GPG_ERR_NO_ERROR) {
88                 pb_log("%s: OpenPGP support not available\n", __func__);
89                 return -1;
90         }
91         err = gpgme_get_engine_info(&enginfo);
92         if (err != GPG_ERR_NO_ERROR) {
93                 pb_log("%s: GPG engine failed to initialize\n", __func__);
94                 return -1;
95         }
96         err = gpgme_new(&gpg_context);
97         if (err != GPG_ERR_NO_ERROR) {
98                 pb_log("%s: GPG context could not be created\n", __func__);
99                 return -1;
100         }
101         err = gpgme_set_protocol(gpg_context, GPGME_PROTOCOL_OpenPGP);
102         if (err != GPG_ERR_NO_ERROR) {
103                 pb_log("%s: GPG protocol could not be set\n", __func__);
104                 return -1;
105         }
106         if (keyring_path)
107                 err = gpgme_ctx_set_engine_info (gpg_context,
108                         GPGME_PROTOCOL_OpenPGP,
109                         enginfo->file_name, keyring_path);
110         else
111                 err = gpgme_ctx_set_engine_info (gpg_context,
112                         GPGME_PROTOCOL_OpenPGP,
113                         enginfo->file_name, enginfo->home_dir);
114         if (err != GPG_ERR_NO_ERROR) {
115                 pb_log("%s: Could not set GPG engine information\n", __func__);
116                 return -1;
117         }
118         err = gpgme_data_new(&plaintext_data);
119         if (err != GPG_ERR_NO_ERROR) {
120                 pb_log("%s: Could not create GPG plaintext data buffer\n",
121                         __func__);
122                 return -1;
123         }
124         err = gpgme_data_new_from_file(&ciphertext_data, filename, 1);
125         if (err != GPG_ERR_NO_ERROR) {
126                 pb_log("%s: Could not create GPG ciphertext data buffer"
127                         " from file '%s'\n", __func__, filename);
128                 return -1;
129         }
130
131         /* Decrypt and verify file */
132         err = gpgme_op_decrypt_verify(gpg_context, ciphertext_data,
133                 plaintext_data);
134         if (err != GPG_ERR_NO_ERROR) {
135                 pb_log("%s: Could not decrypt file\n", __func__);
136                 return -1;
137         }
138         verification_result = gpgme_op_verify_result(gpg_context);
139         verification_signatures = verification_result->signatures;
140         while (verification_signatures) {
141                 if (verification_signatures->status == GPG_ERR_NO_ERROR) {
142                         pb_log("%s: Good signature for key ID '%s' ('%s')\n",
143                                 __func__,
144                                 verification_signatures->fpr, filename);
145                         /* Verify fingerprint is present in authorized
146                          * signatures file
147                          */
148                         char *auth_sig_line = NULL;
149                         size_t auth_sig_len = 0;
150                         ssize_t auth_sig_read;
151                         rewind(authorized_signatures_handle);
152                         while ((auth_sig_read = getline(&auth_sig_line,
153                                 &auth_sig_len,
154                                 authorized_signatures_handle)) != -1) {
155                                 auth_sig_len = strlen(auth_sig_line);
156                                 while ((auth_sig_line[auth_sig_len-1] == '\n')
157                                         || (auth_sig_line[auth_sig_len-1] == '\r'))
158                                         auth_sig_len--;
159                                 auth_sig_line[auth_sig_len] = 0;
160                                 if (strcmp(auth_sig_line,
161                                         verification_signatures->fpr) == 0)
162                                         valid = 1;
163                         }
164                         free(auth_sig_line);
165                 }
166                 else {
167                         pb_log("%s: Signature for key ID '%s' ('%s') invalid."
168                                 "  Status: %08x\n", __func__,
169                                 verification_signatures->fpr, filename,
170                                 verification_signatures->status);
171                 }
172                 verification_signatures = verification_signatures->next;
173         }
174
175         gpgme_data_release(ciphertext_data);
176
177         if (valid) {
178                 /* Write decrypted file over ciphertext */
179                 FILE *plaintext_file_handle = NULL;
180                 plaintext_file_handle = fopen(filename, "wb");
181                 if (!plaintext_file_handle) {
182                         pb_log("%s: Could not create GPG plaintext file '%s'\n",
183                                 __func__, filename);
184                         gpgme_data_release(plaintext_data);
185                         gpgme_release(gpg_context);
186                         return -1;
187                 }
188                 gpgme_data_seek(plaintext_data, 0, SEEK_SET);
189                 if (err != GPG_ERR_NO_ERROR) {
190                         pb_log("%s: Could not seek in GPG plaintext buffer\n",
191                                 __func__);
192                         gpgme_data_release(plaintext_data);
193                         gpgme_release(gpg_context);
194                         fclose(plaintext_file_handle);
195                         return -1;
196                 }
197                 while ((bytes_read = gpgme_data_read(plaintext_data, buffer,
198                         8192)) > 0) {
199                         size_t l2 = fwrite(buffer, 1, bytes_read,
200                                 plaintext_file_handle);
201                         if (l2 < bytes_read) {
202                                 if (ferror(plaintext_file_handle)) {
203                                         /* General error */
204                                         result = -1;
205                                         pb_log("%s: failed: unknown fault\n",
206                                                 __func__);
207                                 }
208                                 else {
209                                         /* No space on destination device */
210                                         result = -1;
211                                         pb_log("%s: failed: temporary storage"
212                                                 " full\n", __func__);
213                                 }
214                                 break;
215                         }
216                 }
217                 fclose(plaintext_file_handle);
218         }
219
220         /* Clean up */
221         gpgme_data_release(plaintext_data);
222         gpgme_release(gpg_context);
223
224         if (!valid) {
225                 pb_log("%s: Incorrect GPG signature\n", __func__);
226                 return -1;
227         }
228
229         pb_log("%s: GPG signature for decrypted file '%s' verified\n",
230                 __func__, filename);
231
232         return result;
233 }
234
235 int verify_file_signature(const char *plaintext_filename,
236         const char *signature_filename, FILE *authorized_signatures_handle,
237         const char *keyring_path)
238 {
239         int valid = 0;
240         gpgme_signature_t verification_signatures;
241         gpgme_verify_result_t verification_result;
242         gpgme_data_t plaintext_data;
243         gpgme_data_t signature_data;
244         gpgme_engine_info_t enginfo;
245         gpgme_ctx_t gpg_context;
246         gpgme_error_t err;
247
248         if (signature_filename == NULL)
249                 return -1;
250
251         /* Initialize gpgme */
252         setlocale (LC_ALL, "");
253         gpgme_check_version(NULL);
254         gpgme_set_locale(NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
255         err = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
256         if (err != GPG_ERR_NO_ERROR) {
257                 pb_log("%s: OpenPGP support not available\n", __func__);
258                 return -1;
259         }
260         err = gpgme_get_engine_info(&enginfo);
261         if (err != GPG_ERR_NO_ERROR) {
262                 pb_log("%s: GPG engine failed to initialize\n", __func__);
263                 return -1;
264         }
265         err = gpgme_new(&gpg_context);
266         if (err != GPG_ERR_NO_ERROR) {
267                 pb_log("%s: GPG context could not be created\n", __func__);
268                 return -1;
269         }
270         err = gpgme_set_protocol(gpg_context, GPGME_PROTOCOL_OpenPGP);
271         if (err != GPG_ERR_NO_ERROR) {
272                 pb_log("%s: GPG protocol could not be set\n", __func__);
273                 return -1;
274         }
275         if (keyring_path)
276                 err = gpgme_ctx_set_engine_info (gpg_context,
277                         GPGME_PROTOCOL_OpenPGP, enginfo->file_name,
278                         keyring_path);
279         else
280                 err = gpgme_ctx_set_engine_info (gpg_context,
281                         GPGME_PROTOCOL_OpenPGP, enginfo->file_name,
282                         enginfo->home_dir);
283         if (err != GPG_ERR_NO_ERROR) {
284                 pb_log("%s: Could not set GPG engine information\n", __func__);
285                 return -1;
286         }
287         err = gpgme_data_new_from_file(&plaintext_data, plaintext_filename, 1);
288         if (err != GPG_ERR_NO_ERROR) {
289                 pb_log("%s: Could not create GPG plaintext data buffer"
290                         " from file '%s'\n", __func__, plaintext_filename);
291                 return -1;
292         }
293         err = gpgme_data_new_from_file(&signature_data, signature_filename, 1);
294         if (err != GPG_ERR_NO_ERROR) {
295                 pb_log("%s: Could not create GPG signature data buffer"
296                         " from file '%s'\n", __func__, signature_filename);
297                 return -1;
298         }
299
300         /* Check signature */
301         err = gpgme_op_verify(gpg_context, signature_data, plaintext_data,
302                 NULL);
303         if (err != GPG_ERR_NO_ERROR) {
304                 pb_log("%s: Could not verify file using GPG signature '%s'\n",
305                         __func__, signature_filename);
306                 return -1;
307         }
308         verification_result = gpgme_op_verify_result(gpg_context);
309         verification_signatures = verification_result->signatures;
310         while (verification_signatures) {
311                 if (verification_signatures->status != GPG_ERR_NO_ERROR) {
312                         /* Signature verification failure */
313                         pb_log("%s: Signature for key ID '%s' ('%s') invalid."
314                                 "  Status: %08x\n", __func__,
315                                 verification_signatures->fpr,
316                                 signature_filename,
317                                 verification_signatures->status);
318                         verification_signatures = verification_signatures->next;
319                         continue;
320                 }
321
322                 /* Signature check passed with no error */
323                 pb_log("%s: Good signature for key ID '%s' ('%s')\n",
324                         __func__, verification_signatures->fpr,
325                         signature_filename);
326                 /* Verify fingerprint is present in
327                         * authorized signatures file
328                         */
329                 char *auth_sig_line = NULL;
330                 size_t auth_sig_len = 0;
331                 ssize_t auth_sig_read;
332                 rewind(authorized_signatures_handle);
333                 while ((auth_sig_read = getline(&auth_sig_line,
334                         &auth_sig_len,
335                         authorized_signatures_handle)) != -1) {
336                         auth_sig_len = strlen(auth_sig_line);
337                         while ((auth_sig_line[auth_sig_len-1] == '\n')
338                                 || (auth_sig_line[auth_sig_len-1] == '\r'))
339                                 auth_sig_len--;
340                         auth_sig_line[auth_sig_len] = '\0';
341                         if (strcmp(auth_sig_line,
342                                 verification_signatures->fpr) == 0)
343                                 valid = 1;
344                 }
345                 free(auth_sig_line);
346                 verification_signatures = verification_signatures->next;
347         }
348
349         /* Clean up */
350         gpgme_data_release(plaintext_data);
351         gpgme_data_release(signature_data);
352         gpgme_release(gpg_context);
353
354         if (!valid) {
355                 pb_log("%s: Incorrect GPG signature\n", __func__);
356                 return -1;
357         }
358
359         pb_log("%s: GPG signature '%s' for file '%s' verified\n",
360                 __func__, signature_filename, plaintext_filename);
361
362         return 0;
363 }
364
365 int gpg_validate_boot_files(struct boot_task *boot_task) {
366         int result = 0;
367         char *kernel_filename = NULL;
368         char *initrd_filename = NULL;
369         char *dtb_filename = NULL;
370
371         FILE *authorized_signatures_handle = NULL;
372
373         char cmdline_template[] = "/tmp/petitbootXXXXXX";
374         int cmdline_fd = mkstemp(cmdline_template);
375         FILE *cmdline_handle = NULL;
376
377         const char* local_initrd_signature = (boot_task->verify_signature) ?
378                 boot_task->local_initrd_signature : NULL;
379         const char* local_dtb_signature = (boot_task->verify_signature) ?
380                 boot_task->local_dtb_signature : NULL;
381         const char* local_image_signature = (boot_task->verify_signature) ?
382                 boot_task->local_image_signature : NULL;
383         const char* local_cmdline_signature =
384                 (boot_task->verify_signature || boot_task->decrypt_files) ?
385                 boot_task->local_cmdline_signature : NULL;
386
387         if ((!boot_task->verify_signature) && (!boot_task->decrypt_files))
388                 return result;
389
390         /* Load authorized signatures file */
391         authorized_signatures_handle = fopen(LOCKDOWN_FILE, "r");
392         if (!authorized_signatures_handle) {
393                 pb_log("%s: unable to read lockdown file\n", __func__);
394                 return KEXEC_LOAD_SIG_SETUP_INVALID;
395         }
396
397         /* Copy files to temporary directory for verification / boot */
398         result = copy_file_secure_dest(boot_task,
399                 boot_task->local_image,
400                 &kernel_filename);
401         if (result) {
402                 pb_log("%s: image copy failed: (%d)\n",
403                         __func__, result);
404                 return result;
405         }
406         if (boot_task->local_initrd) {
407                 result = copy_file_secure_dest(boot_task,
408                         boot_task->local_initrd,
409                         &initrd_filename);
410                 if (result) {
411                         pb_log("%s: initrd copy failed: (%d)\n",
412                                 __func__, result);
413                         return result;
414                 }
415         }
416         if (boot_task->local_dtb) {
417                 result = copy_file_secure_dest(boot_task,
418                         boot_task->local_dtb,
419                         &dtb_filename);
420                 if (result) {
421                         pb_log("%s: dtb copy failed: (%d)\n",
422                                 __func__, result);
423                         return result;
424                 }
425         }
426         boot_task->local_image_override = talloc_strdup(boot_task,
427                 kernel_filename);
428         if (boot_task->local_initrd)
429                 boot_task->local_initrd_override = talloc_strdup(boot_task,
430                         initrd_filename);
431         if (boot_task->local_dtb)
432                 boot_task->local_dtb_override = talloc_strdup(boot_task,
433                         dtb_filename);
434
435         /* Write command line to temporary file for verification */
436         if (cmdline_fd < 0) {
437                 /* mkstemp failed */
438                 pb_log("%s: failed: unable to create command line"
439                         " temporary file for verification\n",
440                         __func__);
441                 result = -1;
442         }
443         else {
444                 cmdline_handle = fdopen(cmdline_fd, "w");
445         }
446         if (!cmdline_handle) {
447                 /* Failed to open file */
448                 pb_log("%s: failed: unable to write command line"
449                         " temporary file for verification\n",
450                         __func__);
451                 result = -1;
452         }
453         else {
454                 fwrite(boot_task->args, sizeof(char),
455                         strlen(boot_task->args), cmdline_handle);
456                 fflush(cmdline_handle);
457         }
458
459         if (boot_task->verify_signature) {
460                 /* Check signatures */
461                 if (verify_file_signature(kernel_filename,
462                         local_image_signature,
463                         authorized_signatures_handle,
464                         "/etc/gpg"))
465                 if (verify_file_signature(cmdline_template,
466                         local_cmdline_signature,
467                         authorized_signatures_handle,
468                         "/etc/gpg"))
469
470                 if (boot_task->local_initrd_signature)
471                         if (verify_file_signature(initrd_filename,
472                                 local_initrd_signature,
473                                 authorized_signatures_handle,
474                                 "/etc/gpg"))
475                                 result = KEXEC_LOAD_SIGNATURE_FAILURE;
476                 if (boot_task->local_dtb_signature)
477                         if (verify_file_signature(dtb_filename,
478                                 local_dtb_signature,
479                                 authorized_signatures_handle,
480                                 "/etc/gpg"))
481                                 result = KEXEC_LOAD_SIGNATURE_FAILURE;
482
483                 /* Clean up */
484                 if (cmdline_handle) {
485                         fclose(cmdline_handle);
486                         unlink(cmdline_template);
487                 }
488                 fclose(authorized_signatures_handle);
489         } else if (boot_task->decrypt_files) {
490                 /* Decrypt files */
491                 if (decrypt_file(kernel_filename,
492                         authorized_signatures_handle,
493                         "/etc/gpg"))
494                         result = KEXEC_LOAD_DECRYPTION_FALURE;
495                 if (verify_file_signature(cmdline_template,
496                         local_cmdline_signature,
497                         authorized_signatures_handle,
498                         "/etc/gpg"))
499                         result = KEXEC_LOAD_SIGNATURE_FAILURE;
500                 if (boot_task->local_initrd)
501                 if (decrypt_file(initrd_filename,
502                                 authorized_signatures_handle,
503                                 "/etc/gpg"))
504                                 result = KEXEC_LOAD_DECRYPTION_FALURE;
505                 if (boot_task->local_dtb)
506                         if (decrypt_file(dtb_filename,
507                                 authorized_signatures_handle,
508                                 "/etc/gpg"))
509                                 result = KEXEC_LOAD_DECRYPTION_FALURE;
510
511                 /* Clean up */
512                 if (cmdline_handle) {
513                         fclose(cmdline_handle);
514                         unlink(cmdline_template);
515                 }
516                 fclose(authorized_signatures_handle);
517         }
518
519         return result;
520 }
521
522 void gpg_validate_boot_files_cleanup(struct boot_task *boot_task) {
523         if ((boot_task->verify_signature) || (boot_task->decrypt_files)) {
524                 unlink(boot_task->local_image_override);
525                 if (boot_task->local_initrd_override)
526                         unlink(boot_task->local_initrd_override);
527                 if (boot_task->local_dtb_override)
528                         unlink(boot_task->local_dtb_override);
529
530                 talloc_free(boot_task->local_image_override);
531                 if (boot_task->local_initrd_override)
532                         talloc_free(boot_task->local_initrd_override);
533                 if (boot_task->local_dtb_override)
534                         talloc_free(boot_task->local_dtb_override);
535         }
536 }
537
538 int lockdown_status() {
539         /* assume most restrictive lockdown type */
540         int ret = PB_LOCKDOWN_SIGN;
541
542         if (access(LOCKDOWN_FILE, F_OK) == -1)
543                 return PB_LOCKDOWN_NONE;
544
545         /* determine lockdown type */
546         FILE *authorized_signatures_handle = NULL;
547         authorized_signatures_handle = fopen(LOCKDOWN_FILE, "r");
548         if (!authorized_signatures_handle)
549                 return ret;
550
551         char *auth_sig_line = NULL;
552         size_t auth_sig_len = 0;
553         ssize_t auth_sig_read;
554         rewind(authorized_signatures_handle);
555         if ((auth_sig_read = getline(&auth_sig_line,
556                 &auth_sig_len,
557                 authorized_signatures_handle)) != -1) {
558                 auth_sig_len = strlen(auth_sig_line);
559                 while ((auth_sig_line[auth_sig_len-1] == '\n')
560                         || (auth_sig_line[auth_sig_len-1] == '\r'))
561                 auth_sig_len--;
562                 auth_sig_line[auth_sig_len] = 0;
563                 if (strcmp(auth_sig_line, "ENCRYPTED") == 0) {
564                         /* first line indicates encrypted files
565                          * expected.  enable decryption.
566                          */
567                         ret = PB_LOCKDOWN_DECRYPT;
568                 }
569         }
570         free(auth_sig_line);
571
572         return ret;
573 }