xref: /openbmc/linux/security/integrity/platform_certs/load_powerpc.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1  // SPDX-License-Identifier: GPL-2.0
2  /*
3   * Copyright (C) 2019 IBM Corporation
4   * Author: Nayna Jain
5   *
6   *      - loads keys and hashes stored and controlled by the firmware.
7   */
8  #include <linux/kernel.h>
9  #include <linux/sched.h>
10  #include <linux/cred.h>
11  #include <linux/err.h>
12  #include <linux/slab.h>
13  #include <asm/secure_boot.h>
14  #include <asm/secvar.h>
15  #include "keyring_handler.h"
16  #include "../integrity.h"
17  
18  #define extract_esl(db, data, size, offset)	\
19  	do { db = data + offset; size = size - offset; } while (0)
20  
21  /*
22   * Get a certificate list blob from the named secure variable.
23   *
24   * Returns:
25   *  - a pointer to a kmalloc'd buffer containing the cert list on success
26   *  - NULL if the key does not exist
27   *  - an ERR_PTR on error
28   */
get_cert_list(u8 * key,unsigned long keylen,u64 * size)29  static __init void *get_cert_list(u8 *key, unsigned long keylen, u64 *size)
30  {
31  	int rc;
32  	void *db;
33  
34  	rc = secvar_ops->get(key, keylen, NULL, size);
35  	if (rc) {
36  		if (rc == -ENOENT)
37  			return NULL;
38  		return ERR_PTR(rc);
39  	}
40  
41  	db = kmalloc(*size, GFP_KERNEL);
42  	if (!db)
43  		return ERR_PTR(-ENOMEM);
44  
45  	rc = secvar_ops->get(key, keylen, db, size);
46  	if (rc) {
47  		kfree(db);
48  		return ERR_PTR(rc);
49  	}
50  
51  	return db;
52  }
53  
54  /*
55   * Load the certs contained in the keys databases into the platform trusted
56   * keyring and the blacklisted X.509 cert SHA256 hashes into the blacklist
57   * keyring.
58   */
load_powerpc_certs(void)59  static int __init load_powerpc_certs(void)
60  {
61  	void *db = NULL, *dbx = NULL, *data = NULL;
62  	void *trustedca;
63  	void *moduledb;
64  	u64 dsize = 0;
65  	u64 offset = 0;
66  	int rc = 0;
67  	ssize_t len;
68  	char buf[32];
69  
70  	if (!secvar_ops)
71  		return -ENODEV;
72  
73  	len = secvar_ops->format(buf, sizeof(buf));
74  	if (len <= 0)
75  		return -ENODEV;
76  
77  	// Check for known secure boot implementations from OPAL or PLPKS
78  	if (strcmp("ibm,edk2-compat-v1", buf) && strcmp("ibm,plpks-sb-v1", buf)) {
79  		pr_err("Unsupported secvar implementation \"%s\", not loading certs\n", buf);
80  		return -ENODEV;
81  	}
82  
83  	if (strcmp("ibm,plpks-sb-v1", buf) == 0)
84  		/* PLPKS authenticated variables ESL data is prefixed with 8 bytes of timestamp */
85  		offset = 8;
86  
87  	/*
88  	 * Get db, and dbx. They might not exist, so it isn't an error if we
89  	 * can't get them.
90  	 */
91  	data = get_cert_list("db", 3, &dsize);
92  	if (!data) {
93  		pr_info("Couldn't get db list from firmware\n");
94  	} else if (IS_ERR(data)) {
95  		rc = PTR_ERR(data);
96  		pr_err("Error reading db from firmware: %d\n", rc);
97  		return rc;
98  	} else {
99  		extract_esl(db, data, dsize, offset);
100  
101  		rc = parse_efi_signature_list("powerpc:db", db, dsize,
102  					      get_handler_for_db);
103  		if (rc)
104  			pr_err("Couldn't parse db signatures: %d\n", rc);
105  		kfree(data);
106  	}
107  
108  	data = get_cert_list("dbx", 4,  &dsize);
109  	if (!data) {
110  		pr_info("Couldn't get dbx list from firmware\n");
111  	} else if (IS_ERR(data)) {
112  		rc = PTR_ERR(data);
113  		pr_err("Error reading dbx from firmware: %d\n", rc);
114  		return rc;
115  	} else {
116  		extract_esl(dbx, data, dsize, offset);
117  
118  		rc = parse_efi_signature_list("powerpc:dbx", dbx, dsize,
119  					      get_handler_for_dbx);
120  		if (rc)
121  			pr_err("Couldn't parse dbx signatures: %d\n", rc);
122  		kfree(data);
123  	}
124  
125  	data = get_cert_list("trustedcadb", 12,  &dsize);
126  	if (!data) {
127  		pr_info("Couldn't get trustedcadb list from firmware\n");
128  	} else if (IS_ERR(data)) {
129  		rc = PTR_ERR(data);
130  		pr_err("Error reading trustedcadb from firmware: %d\n", rc);
131  	} else {
132  		extract_esl(trustedca, data, dsize, offset);
133  
134  		rc = parse_efi_signature_list("powerpc:trustedca", trustedca, dsize,
135  					      get_handler_for_ca_keys);
136  		if (rc)
137  			pr_err("Couldn't parse trustedcadb signatures: %d\n", rc);
138  		kfree(data);
139  	}
140  
141  	data = get_cert_list("moduledb", 9,  &dsize);
142  	if (!data) {
143  		pr_info("Couldn't get moduledb list from firmware\n");
144  	} else if (IS_ERR(data)) {
145  		rc = PTR_ERR(data);
146  		pr_err("Error reading moduledb from firmware: %d\n", rc);
147  	} else {
148  		extract_esl(moduledb, data, dsize, offset);
149  
150  		rc = parse_efi_signature_list("powerpc:moduledb", moduledb, dsize,
151  					      get_handler_for_code_signing_keys);
152  		if (rc)
153  			pr_err("Couldn't parse moduledb signatures: %d\n", rc);
154  		kfree(data);
155  	}
156  
157  	return rc;
158  }
159  late_initcall(load_powerpc_certs);
160