lib/crypt: Add helpers for operating on /etc/shadow
[petitboot] / lib / security / common.c
1 /*
2  *  Copyright (C) 2016 Raptor Engineering, LLC
3  *  Copyright (C) 2018 Opengear, Inc
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; version 2 of the License.
8  *
9  *  This program 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
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19 #if defined(HAVE_CONFIG_H)
20 #include "config.h"
21 #endif
22
23 #include <stdbool.h>
24 #include <stdlib.h>
25 #include <assert.h>
26 #include <dirent.h>
27 #include <string.h>
28 #include <fcntl.h>
29 #include <locale.h>
30 #include <sys/types.h>
31
32 #include <log/log.h>
33 #include <file/file.h>
34 #include <talloc/talloc.h>
35 #include <url/url.h>
36 #include <util/util.h>
37 #include <i18n/i18n.h>
38
39 #include "security.h"
40
41 struct pb_url * get_signature_url(void *ctx, struct pb_url *base_file)
42 {
43         struct pb_url *signature_file = NULL;
44
45         signature_file = pb_url_copy(ctx, base_file);
46         talloc_free(signature_file->file);
47         signature_file->file = talloc_asprintf(signature_file,
48                 "%s.sig", base_file->file);
49         talloc_free(signature_file->path);
50         signature_file->path = talloc_asprintf(signature_file,
51                 "%s.sig", base_file->path);
52
53         return signature_file;
54 }
55
56 int validate_boot_files(struct boot_task *boot_task) {
57     int result = 0;
58     char *kernel_filename = NULL;
59     char *initrd_filename = NULL;
60     char *dtb_filename = NULL;
61
62     FILE *authorized_signatures_handle = NULL;
63
64     char cmdline_template[] = "/tmp/petitbootXXXXXX";
65     int cmdline_fd = mkstemp(cmdline_template);
66     FILE *cmdline_handle = NULL;
67
68     const char* local_initrd_signature = (boot_task->verify_signature) ?
69         boot_task->local_initrd_signature : NULL;
70     const char* local_dtb_signature = (boot_task->verify_signature) ?
71         boot_task->local_dtb_signature : NULL;
72     const char* local_image_signature = (boot_task->verify_signature) ?
73         boot_task->local_image_signature : NULL;
74     const char* local_cmdline_signature =
75         (boot_task->verify_signature || boot_task->decrypt_files) ?
76         boot_task->local_cmdline_signature : NULL;
77
78     if ((!boot_task->verify_signature) && (!boot_task->decrypt_files))
79         return result;
80
81     /* Load authorized signatures file */
82     authorized_signatures_handle = fopen(LOCKDOWN_FILE, "r");
83     if (!authorized_signatures_handle) {
84         pb_log_fn("unable to read lockdown file\n");
85         return KEXEC_LOAD_SIG_SETUP_INVALID;
86     }
87
88     /* Copy files to temporary directory for verification / boot */
89     result = copy_file_secure_dest(boot_task,
90         boot_task->local_image,
91         &kernel_filename);
92     if (result) {
93         pb_log("%s: image copy failed: (%d)\n",
94             __func__, result);
95         return result;
96     }
97     if (boot_task->local_initrd) {
98         result = copy_file_secure_dest(boot_task,
99             boot_task->local_initrd,
100             &initrd_filename);
101         if (result) {
102             pb_log("%s: initrd copy failed: (%d)\n",
103                 __func__, result);
104             return result;
105         }
106     }
107     if (boot_task->local_dtb) {
108         result = copy_file_secure_dest(boot_task,
109             boot_task->local_dtb,
110             &dtb_filename);
111         if (result) {
112             pb_log("%s: dtb copy failed: (%d)\n",
113                 __func__, result);
114             return result;
115         }
116     }
117     boot_task->local_image_override = talloc_strdup(boot_task,
118         kernel_filename);
119     if (boot_task->local_initrd)
120         boot_task->local_initrd_override = talloc_strdup(boot_task,
121             initrd_filename);
122     if (boot_task->local_dtb)
123         boot_task->local_dtb_override = talloc_strdup(boot_task,
124             dtb_filename);
125
126     /* Write command line to temporary file for verification */
127     if (cmdline_fd < 0) {
128         /* mkstemp failed */
129         pb_log("%s: failed: unable to create command line"
130             " temporary file for verification\n",
131             __func__);
132         result = -1;
133     }
134     else {
135         cmdline_handle = fdopen(cmdline_fd, "w");
136     }
137     if (!cmdline_handle) {
138         /* Failed to open file */
139         pb_log("%s: failed: unable to write command line"
140             " temporary file for verification\n",
141             __func__);
142         result = -1;
143     }
144     else {
145         fwrite(boot_task->args, sizeof(char),
146             strlen(boot_task->args), cmdline_handle);
147         fflush(cmdline_handle);
148     }
149
150     if (boot_task->verify_signature) {
151         /* Check signatures */
152         if (verify_file_signature(kernel_filename,
153             local_image_signature,
154             authorized_signatures_handle,
155             KEYRING_PATH))
156             result = KEXEC_LOAD_SIGNATURE_FAILURE;
157         if (verify_file_signature(cmdline_template,
158             local_cmdline_signature,
159             authorized_signatures_handle,
160             KEYRING_PATH))
161             result = KEXEC_LOAD_SIGNATURE_FAILURE;
162
163         if (boot_task->local_initrd_signature)
164             if (verify_file_signature(initrd_filename,
165                 local_initrd_signature,
166                 authorized_signatures_handle,
167                 KEYRING_PATH))
168                 result = KEXEC_LOAD_SIGNATURE_FAILURE;
169         if (boot_task->local_dtb_signature)
170             if (verify_file_signature(dtb_filename,
171                 local_dtb_signature,
172                 authorized_signatures_handle,
173                 KEYRING_PATH))
174                 result = KEXEC_LOAD_SIGNATURE_FAILURE;
175
176         /* Clean up */
177         if (cmdline_handle) {
178             fclose(cmdline_handle);
179             unlink(cmdline_template);
180         }
181         fclose(authorized_signatures_handle);
182     } else if (boot_task->decrypt_files) {
183         /* Decrypt files */
184         if (decrypt_file(kernel_filename,
185             authorized_signatures_handle,
186             KEYRING_PATH))
187             result = KEXEC_LOAD_DECRYPTION_FALURE;
188         if (verify_file_signature(cmdline_template,
189             local_cmdline_signature,
190             authorized_signatures_handle,
191             KEYRING_PATH))
192             result = KEXEC_LOAD_SIGNATURE_FAILURE;
193         if (boot_task->local_initrd)
194             if (decrypt_file(initrd_filename,
195                 authorized_signatures_handle,
196                 KEYRING_PATH))
197                 result = KEXEC_LOAD_DECRYPTION_FALURE;
198         if (boot_task->local_dtb)
199             if (decrypt_file(dtb_filename,
200                 authorized_signatures_handle,
201                 KEYRING_PATH))
202                 result = KEXEC_LOAD_DECRYPTION_FALURE;
203
204         /* Clean up */
205         if (cmdline_handle) {
206             fclose(cmdline_handle);
207             unlink(cmdline_template);
208         }
209         fclose(authorized_signatures_handle);
210     }
211
212     return result;
213 }
214
215 void validate_boot_files_cleanup(struct boot_task *boot_task) {
216         if ((boot_task->verify_signature) || (boot_task->decrypt_files)) {
217                 unlink(boot_task->local_image_override);
218                 if (boot_task->local_initrd_override)
219                         unlink(boot_task->local_initrd_override);
220                 if (boot_task->local_dtb_override)
221                         unlink(boot_task->local_dtb_override);
222
223                 talloc_free(boot_task->local_image_override);
224                 if (boot_task->local_initrd_override)
225                         talloc_free(boot_task->local_initrd_override);
226                 if (boot_task->local_dtb_override)
227                         talloc_free(boot_task->local_dtb_override);
228         }
229 }
230