2 * Copyright (C) 2016 Raptor Engineering, LLC
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.
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.
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
18 #if defined(HAVE_CONFIG_H)
28 #include <sys/types.h>
31 #include <file/file.h>
32 #include <talloc/talloc.h>
34 #include <util/util.h>
35 #include <i18n/i18n.h>
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.
48 struct pb_url * gpg_get_signature_url(void *ctx, struct pb_url *base_file)
50 struct pb_url *signature_file = NULL;
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);
60 return signature_file;
63 int verify_file_signature(const char *plaintext_filename,
64 const char *signature_filename, FILE *authorized_signatures_handle,
65 const char *keyring_path)
68 gpgme_signature_t verification_signatures;
69 gpgme_verify_result_t verification_result;
70 gpgme_data_t plaintext_data;
71 gpgme_data_t signature_data;
72 gpgme_engine_info_t enginfo;
73 gpgme_ctx_t gpg_context;
76 if (signature_filename == NULL)
79 /* Initialize gpgme */
80 setlocale (LC_ALL, "");
81 gpgme_check_version(NULL);
82 gpgme_set_locale(NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
83 err = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
84 if (err != GPG_ERR_NO_ERROR) {
85 pb_log("%s: OpenPGP support not available\n", __func__);
88 err = gpgme_get_engine_info(&enginfo);
89 if (err != GPG_ERR_NO_ERROR) {
90 pb_log("%s: GPG engine failed to initialize\n", __func__);
93 err = gpgme_new(&gpg_context);
94 if (err != GPG_ERR_NO_ERROR) {
95 pb_log("%s: GPG context could not be created\n", __func__);
98 err = gpgme_set_protocol(gpg_context, GPGME_PROTOCOL_OpenPGP);
99 if (err != GPG_ERR_NO_ERROR) {
100 pb_log("%s: GPG protocol could not be set\n", __func__);
104 err = gpgme_ctx_set_engine_info (gpg_context,
105 GPGME_PROTOCOL_OpenPGP, enginfo->file_name,
108 err = gpgme_ctx_set_engine_info (gpg_context,
109 GPGME_PROTOCOL_OpenPGP, enginfo->file_name,
111 if (err != GPG_ERR_NO_ERROR) {
112 pb_log("%s: Could not set GPG engine information\n", __func__);
115 err = gpgme_data_new_from_file(&plaintext_data, plaintext_filename, 1);
116 if (err != GPG_ERR_NO_ERROR) {
117 pb_log("%s: Could not create GPG plaintext data buffer"
118 " from file '%s'\n", __func__, plaintext_filename);
121 err = gpgme_data_new_from_file(&signature_data, signature_filename, 1);
122 if (err != GPG_ERR_NO_ERROR) {
123 pb_log("%s: Could not create GPG signature data buffer"
124 " from file '%s'\n", __func__, signature_filename);
128 /* Check signature */
129 err = gpgme_op_verify(gpg_context, signature_data, plaintext_data,
131 if (err != GPG_ERR_NO_ERROR) {
132 pb_log("%s: Could not verify file using GPG signature '%s'\n",
133 __func__, signature_filename);
136 verification_result = gpgme_op_verify_result(gpg_context);
137 verification_signatures = verification_result->signatures;
138 while (verification_signatures) {
139 if (verification_signatures->status != GPG_ERR_NO_ERROR) {
140 /* Signature verification failure */
141 pb_log("%s: Signature for key ID '%s' ('%s') invalid."
142 " Status: %08x\n", __func__,
143 verification_signatures->fpr,
145 verification_signatures->status);
146 verification_signatures = verification_signatures->next;
150 /* Signature check passed with no error */
151 pb_log("%s: Good signature for key ID '%s' ('%s')\n",
152 __func__, verification_signatures->fpr,
154 /* Verify fingerprint is present in
155 * authorized signatures file
157 char *auth_sig_line = NULL;
158 size_t auth_sig_len = 0;
159 ssize_t auth_sig_read;
160 rewind(authorized_signatures_handle);
161 while ((auth_sig_read = getline(&auth_sig_line,
163 authorized_signatures_handle)) != -1) {
164 auth_sig_len = strlen(auth_sig_line);
165 while ((auth_sig_line[auth_sig_len-1] == '\n')
166 || (auth_sig_line[auth_sig_len-1] == '\r'))
168 auth_sig_line[auth_sig_len] = '\0';
169 if (strcmp(auth_sig_line,
170 verification_signatures->fpr) == 0)
174 verification_signatures = verification_signatures->next;
178 gpgme_data_release(plaintext_data);
179 gpgme_data_release(signature_data);
180 gpgme_release(gpg_context);
183 pb_log("%s: Incorrect GPG signature\n", __func__);
187 pb_log("%s: GPG signature '%s' for file '%s' verified\n",
188 __func__, signature_filename, plaintext_filename);
193 int gpg_validate_boot_files(struct boot_task *boot_task) {
195 char *kernel_filename = NULL;
196 char *initrd_filename = NULL;
197 char *dtb_filename = NULL;
199 FILE *authorized_signatures_handle = NULL;
201 char cmdline_template[] = "/tmp/petitbootXXXXXX";
202 int cmdline_fd = mkstemp(cmdline_template);
203 FILE *cmdline_handle = NULL;
205 const char* local_initrd_signature = (boot_task->verify_signature) ?
206 boot_task->local_initrd_signature : NULL;
207 const char* local_dtb_signature = (boot_task->verify_signature) ?
208 boot_task->local_dtb_signature : NULL;
209 const char* local_image_signature = (boot_task->verify_signature) ?
210 boot_task->local_image_signature : NULL;
211 const char* local_cmdline_signature = (boot_task->verify_signature) ?
212 boot_task->local_cmdline_signature : NULL;
214 if (!boot_task->verify_signature)
217 /* Load authorized signatures file */
218 authorized_signatures_handle = fopen(LOCKDOWN_FILE, "r");
219 if (!authorized_signatures_handle) {
220 pb_log("%s: unable to read lockdown file\n", __func__);
221 return KEXEC_LOAD_SIG_SETUP_INVALID;
224 /* Copy files to temporary directory for verification / boot */
225 result = copy_file_secure_dest(boot_task,
226 boot_task->local_image,
229 pb_log("%s: image copy failed: (%d)\n",
233 if (boot_task->local_initrd) {
234 result = copy_file_secure_dest(boot_task,
235 boot_task->local_initrd,
238 pb_log("%s: initrd copy failed: (%d)\n",
243 if (boot_task->local_dtb) {
244 result = copy_file_secure_dest(boot_task,
245 boot_task->local_dtb,
248 pb_log("%s: dtb copy failed: (%d)\n",
253 boot_task->local_image_override = talloc_strdup(boot_task,
255 if (boot_task->local_initrd)
256 boot_task->local_initrd_override = talloc_strdup(boot_task,
258 if (boot_task->local_dtb)
259 boot_task->local_dtb_override = talloc_strdup(boot_task,
262 /* Write command line to temporary file for verification */
263 if (cmdline_fd < 0) {
265 pb_log("%s: failed: unable to create command line"
266 " temporary file for verification\n",
271 cmdline_handle = fdopen(cmdline_fd, "w");
273 if (!cmdline_handle) {
274 /* Failed to open file */
275 pb_log("%s: failed: unable to write command line"
276 " temporary file for verification\n",
281 fwrite(boot_task->args, sizeof(char),
282 strlen(boot_task->args), cmdline_handle);
283 fflush(cmdline_handle);
286 /* Check signatures */
287 if (verify_file_signature(kernel_filename,
288 local_image_signature,
289 authorized_signatures_handle, "/etc/gpg"))
290 result = KEXEC_LOAD_SIGNATURE_FAILURE;
291 if (verify_file_signature(cmdline_template,
292 local_cmdline_signature,
293 authorized_signatures_handle, "/etc/gpg"))
294 result = KEXEC_LOAD_SIGNATURE_FAILURE;
295 if (boot_task->local_initrd_signature)
296 if (verify_file_signature(initrd_filename,
297 local_initrd_signature,
298 authorized_signatures_handle, "/etc/gpg"))
299 result = KEXEC_LOAD_SIGNATURE_FAILURE;
300 if (boot_task->local_dtb_signature)
301 if (verify_file_signature(dtb_filename,
303 authorized_signatures_handle, "/etc/gpg"))
304 result = KEXEC_LOAD_SIGNATURE_FAILURE;
307 if (cmdline_handle) {
308 fclose(cmdline_handle);
309 unlink(cmdline_template);
311 fclose(authorized_signatures_handle);
316 void gpg_validate_boot_files_cleanup(struct boot_task *boot_task) {
317 if (boot_task->verify_signature) {
318 unlink(boot_task->local_image_override);
319 if (boot_task->local_initrd_override)
320 unlink(boot_task->local_initrd_override);
321 if (boot_task->local_dtb_override)
322 unlink(boot_task->local_dtb_override);
324 talloc_free(boot_task->local_image_override);
325 if (boot_task->local_initrd_override)
326 talloc_free(boot_task->local_initrd_override);
327 if (boot_task->local_dtb_override)
328 talloc_free(boot_task->local_dtb_override);
332 int lockdown_status() {
333 if (access(LOCKDOWN_FILE, F_OK) == -1)
334 return PB_LOCKDOWN_NONE;
336 return PB_LOCKDOWN_SIGN;