xref: /openbmc/linux/security/integrity/platform_certs/load_powerpc.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
18220e22dSNayna Jain // SPDX-License-Identifier: GPL-2.0
28220e22dSNayna Jain /*
38220e22dSNayna Jain  * Copyright (C) 2019 IBM Corporation
48220e22dSNayna Jain  * Author: Nayna Jain
58220e22dSNayna Jain  *
68220e22dSNayna Jain  *      - loads keys and hashes stored and controlled by the firmware.
78220e22dSNayna Jain  */
88220e22dSNayna Jain #include <linux/kernel.h>
98220e22dSNayna Jain #include <linux/sched.h>
108220e22dSNayna Jain #include <linux/cred.h>
118220e22dSNayna Jain #include <linux/err.h>
128220e22dSNayna Jain #include <linux/slab.h>
138220e22dSNayna Jain #include <asm/secure_boot.h>
148220e22dSNayna Jain #include <asm/secvar.h>
158220e22dSNayna Jain #include "keyring_handler.h"
163c8069b0SRussell Currey #include "../integrity.h"
178220e22dSNayna Jain 
18e66effafSNayna Jain #define extract_esl(db, data, size, offset)	\
19e66effafSNayna Jain 	do { db = data + offset; size = size - offset; } while (0)
20e66effafSNayna Jain 
218220e22dSNayna Jain /*
228220e22dSNayna Jain  * Get a certificate list blob from the named secure variable.
233c8069b0SRussell Currey  *
243c8069b0SRussell Currey  * Returns:
253c8069b0SRussell Currey  *  - a pointer to a kmalloc'd buffer containing the cert list on success
263c8069b0SRussell Currey  *  - NULL if the key does not exist
273c8069b0SRussell Currey  *  - an ERR_PTR on error
288220e22dSNayna Jain  */
get_cert_list(u8 * key,unsigned long keylen,u64 * size)2953cea34bSMichael Ellerman static __init void *get_cert_list(u8 *key, unsigned long keylen, u64 *size)
308220e22dSNayna Jain {
318220e22dSNayna Jain 	int rc;
328220e22dSNayna Jain 	void *db;
338220e22dSNayna Jain 
348220e22dSNayna Jain 	rc = secvar_ops->get(key, keylen, NULL, size);
358220e22dSNayna Jain 	if (rc) {
363c8069b0SRussell Currey 		if (rc == -ENOENT)
378220e22dSNayna Jain 			return NULL;
383c8069b0SRussell Currey 		return ERR_PTR(rc);
398220e22dSNayna Jain 	}
408220e22dSNayna Jain 
418220e22dSNayna Jain 	db = kmalloc(*size, GFP_KERNEL);
428220e22dSNayna Jain 	if (!db)
433c8069b0SRussell Currey 		return ERR_PTR(-ENOMEM);
448220e22dSNayna Jain 
458220e22dSNayna Jain 	rc = secvar_ops->get(key, keylen, db, size);
468220e22dSNayna Jain 	if (rc) {
478220e22dSNayna Jain 		kfree(db);
483c8069b0SRussell Currey 		return ERR_PTR(rc);
498220e22dSNayna Jain 	}
508220e22dSNayna Jain 
518220e22dSNayna Jain 	return db;
528220e22dSNayna Jain }
538220e22dSNayna Jain 
548220e22dSNayna Jain /*
558220e22dSNayna Jain  * Load the certs contained in the keys databases into the platform trusted
568220e22dSNayna Jain  * keyring and the blacklisted X.509 cert SHA256 hashes into the blacklist
578220e22dSNayna Jain  * keyring.
588220e22dSNayna Jain  */
load_powerpc_certs(void)598220e22dSNayna Jain static int __init load_powerpc_certs(void)
608220e22dSNayna Jain {
61e66effafSNayna Jain 	void *db = NULL, *dbx = NULL, *data = NULL;
62a3af7188SNayna Jain 	void *trustedca;
63*44e69ea5SNayna Jain 	void *moduledb;
64e66effafSNayna Jain 	u64 dsize = 0;
65e66effafSNayna Jain 	u64 offset = 0;
668220e22dSNayna Jain 	int rc = 0;
674b3e71e9SRussell Currey 	ssize_t len;
684b3e71e9SRussell Currey 	char buf[32];
698220e22dSNayna Jain 
708220e22dSNayna Jain 	if (!secvar_ops)
718220e22dSNayna Jain 		return -ENODEV;
728220e22dSNayna Jain 
734b3e71e9SRussell Currey 	len = secvar_ops->format(buf, sizeof(buf));
744b3e71e9SRussell Currey 	if (len <= 0)
758220e22dSNayna Jain 		return -ENODEV;
768220e22dSNayna Jain 
774b3e71e9SRussell Currey 	// Check for known secure boot implementations from OPAL or PLPKS
784b3e71e9SRussell Currey 	if (strcmp("ibm,edk2-compat-v1", buf) && strcmp("ibm,plpks-sb-v1", buf)) {
794b3e71e9SRussell Currey 		pr_err("Unsupported secvar implementation \"%s\", not loading certs\n", buf);
804b3e71e9SRussell Currey 		return -ENODEV;
814b3e71e9SRussell Currey 	}
824b3e71e9SRussell Currey 
83e66effafSNayna Jain 	if (strcmp("ibm,plpks-sb-v1", buf) == 0)
84e66effafSNayna Jain 		/* PLPKS authenticated variables ESL data is prefixed with 8 bytes of timestamp */
85e66effafSNayna Jain 		offset = 8;
86e66effafSNayna Jain 
878220e22dSNayna Jain 	/*
888220e22dSNayna Jain 	 * Get db, and dbx. They might not exist, so it isn't an error if we
898220e22dSNayna Jain 	 * can't get them.
908220e22dSNayna Jain 	 */
91e66effafSNayna Jain 	data = get_cert_list("db", 3, &dsize);
92e66effafSNayna Jain 	if (!data) {
933c8069b0SRussell Currey 		pr_info("Couldn't get db list from firmware\n");
94e66effafSNayna Jain 	} else if (IS_ERR(data)) {
95e66effafSNayna Jain 		rc = PTR_ERR(data);
963c8069b0SRussell Currey 		pr_err("Error reading db from firmware: %d\n", rc);
973c8069b0SRussell Currey 		return rc;
988220e22dSNayna Jain 	} else {
99e66effafSNayna Jain 		extract_esl(db, data, dsize, offset);
100e66effafSNayna Jain 
101e66effafSNayna Jain 		rc = parse_efi_signature_list("powerpc:db", db, dsize,
1028220e22dSNayna Jain 					      get_handler_for_db);
1038220e22dSNayna Jain 		if (rc)
1048220e22dSNayna Jain 			pr_err("Couldn't parse db signatures: %d\n", rc);
105e66effafSNayna Jain 		kfree(data);
1068220e22dSNayna Jain 	}
1078220e22dSNayna Jain 
108e66effafSNayna Jain 	data = get_cert_list("dbx", 4,  &dsize);
109e66effafSNayna Jain 	if (!data) {
1108220e22dSNayna Jain 		pr_info("Couldn't get dbx list from firmware\n");
111e66effafSNayna Jain 	} else if (IS_ERR(data)) {
112e66effafSNayna Jain 		rc = PTR_ERR(data);
1133c8069b0SRussell Currey 		pr_err("Error reading dbx from firmware: %d\n", rc);
1143c8069b0SRussell Currey 		return rc;
1158220e22dSNayna Jain 	} else {
116e66effafSNayna Jain 		extract_esl(dbx, data, dsize, offset);
117e66effafSNayna Jain 
118e66effafSNayna Jain 		rc = parse_efi_signature_list("powerpc:dbx", dbx, dsize,
1198220e22dSNayna Jain 					      get_handler_for_dbx);
1208220e22dSNayna Jain 		if (rc)
1218220e22dSNayna Jain 			pr_err("Couldn't parse dbx signatures: %d\n", rc);
122e66effafSNayna Jain 		kfree(data);
1238220e22dSNayna Jain 	}
1248220e22dSNayna Jain 
125a3af7188SNayna Jain 	data = get_cert_list("trustedcadb", 12,  &dsize);
126a3af7188SNayna Jain 	if (!data) {
127a3af7188SNayna Jain 		pr_info("Couldn't get trustedcadb list from firmware\n");
128a3af7188SNayna Jain 	} else if (IS_ERR(data)) {
129a3af7188SNayna Jain 		rc = PTR_ERR(data);
130a3af7188SNayna Jain 		pr_err("Error reading trustedcadb from firmware: %d\n", rc);
131a3af7188SNayna Jain 	} else {
132a3af7188SNayna Jain 		extract_esl(trustedca, data, dsize, offset);
133a3af7188SNayna Jain 
134a3af7188SNayna Jain 		rc = parse_efi_signature_list("powerpc:trustedca", trustedca, dsize,
135a3af7188SNayna Jain 					      get_handler_for_ca_keys);
136a3af7188SNayna Jain 		if (rc)
137a3af7188SNayna Jain 			pr_err("Couldn't parse trustedcadb signatures: %d\n", rc);
138a3af7188SNayna Jain 		kfree(data);
139a3af7188SNayna Jain 	}
140a3af7188SNayna Jain 
141*44e69ea5SNayna Jain 	data = get_cert_list("moduledb", 9,  &dsize);
142*44e69ea5SNayna Jain 	if (!data) {
143*44e69ea5SNayna Jain 		pr_info("Couldn't get moduledb list from firmware\n");
144*44e69ea5SNayna Jain 	} else if (IS_ERR(data)) {
145*44e69ea5SNayna Jain 		rc = PTR_ERR(data);
146*44e69ea5SNayna Jain 		pr_err("Error reading moduledb from firmware: %d\n", rc);
147*44e69ea5SNayna Jain 	} else {
148*44e69ea5SNayna Jain 		extract_esl(moduledb, data, dsize, offset);
149*44e69ea5SNayna Jain 
150*44e69ea5SNayna Jain 		rc = parse_efi_signature_list("powerpc:moduledb", moduledb, dsize,
151*44e69ea5SNayna Jain 					      get_handler_for_code_signing_keys);
152*44e69ea5SNayna Jain 		if (rc)
153*44e69ea5SNayna Jain 			pr_err("Couldn't parse moduledb signatures: %d\n", rc);
154*44e69ea5SNayna Jain 		kfree(data);
155*44e69ea5SNayna Jain 	}
156*44e69ea5SNayna Jain 
1578220e22dSNayna Jain 	return rc;
1588220e22dSNayna Jain }
1598220e22dSNayna Jain late_initcall(load_powerpc_certs);
160