xref: /linux/tools/bpf/bpftool/sign.c (revision 4f38da1f027ea2c9f01bb71daa7a299c191b6940)
1*40863f4dSKP Singh // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2*40863f4dSKP Singh /*
3*40863f4dSKP Singh  * Copyright (C) 2025 Google LLC.
4*40863f4dSKP Singh  */
5*40863f4dSKP Singh 
6*40863f4dSKP Singh #ifndef _GNU_SOURCE
7*40863f4dSKP Singh #define _GNU_SOURCE
8*40863f4dSKP Singh #endif
9*40863f4dSKP Singh #include <stdio.h>
10*40863f4dSKP Singh #include <stdlib.h>
11*40863f4dSKP Singh #include <stdint.h>
12*40863f4dSKP Singh #include <stdbool.h>
13*40863f4dSKP Singh #include <string.h>
14*40863f4dSKP Singh #include <getopt.h>
15*40863f4dSKP Singh #include <err.h>
16*40863f4dSKP Singh #include <openssl/opensslv.h>
17*40863f4dSKP Singh #include <openssl/bio.h>
18*40863f4dSKP Singh #include <openssl/evp.h>
19*40863f4dSKP Singh #include <openssl/pem.h>
20*40863f4dSKP Singh #include <openssl/err.h>
21*40863f4dSKP Singh #include <openssl/cms.h>
22*40863f4dSKP Singh #include <linux/keyctl.h>
23*40863f4dSKP Singh #include <errno.h>
24*40863f4dSKP Singh 
25*40863f4dSKP Singh #include <bpf/skel_internal.h>
26*40863f4dSKP Singh 
27*40863f4dSKP Singh #include "main.h"
28*40863f4dSKP Singh 
29*40863f4dSKP Singh #define OPEN_SSL_ERR_BUF_LEN 256
30*40863f4dSKP Singh 
31*40863f4dSKP Singh static void display_openssl_errors(int l)
32*40863f4dSKP Singh {
33*40863f4dSKP Singh 	char buf[OPEN_SSL_ERR_BUF_LEN];
34*40863f4dSKP Singh 	const char *file;
35*40863f4dSKP Singh 	const char *data;
36*40863f4dSKP Singh 	unsigned long e;
37*40863f4dSKP Singh 	int flags;
38*40863f4dSKP Singh 	int line;
39*40863f4dSKP Singh 
40*40863f4dSKP Singh 	while ((e = ERR_get_error_all(&file, &line, NULL, &data, &flags))) {
41*40863f4dSKP Singh 		ERR_error_string_n(e, buf, sizeof(buf));
42*40863f4dSKP Singh 		if (data && (flags & ERR_TXT_STRING)) {
43*40863f4dSKP Singh 			p_err("OpenSSL %s: %s:%d: %s", buf, file, line, data);
44*40863f4dSKP Singh 		} else {
45*40863f4dSKP Singh 			p_err("OpenSSL %s: %s:%d", buf, file, line);
46*40863f4dSKP Singh 		}
47*40863f4dSKP Singh 	}
48*40863f4dSKP Singh }
49*40863f4dSKP Singh 
50*40863f4dSKP Singh #define DISPLAY_OSSL_ERR(cond)				 \
51*40863f4dSKP Singh 	do {						 \
52*40863f4dSKP Singh 		bool __cond = (cond);			 \
53*40863f4dSKP Singh 		if (__cond && ERR_peek_error())		 \
54*40863f4dSKP Singh 			display_openssl_errors(__LINE__);\
55*40863f4dSKP Singh 	} while (0)
56*40863f4dSKP Singh 
57*40863f4dSKP Singh static EVP_PKEY *read_private_key(const char *pkey_path)
58*40863f4dSKP Singh {
59*40863f4dSKP Singh 	EVP_PKEY *private_key = NULL;
60*40863f4dSKP Singh 	BIO *b;
61*40863f4dSKP Singh 
62*40863f4dSKP Singh 	b = BIO_new_file(pkey_path, "rb");
63*40863f4dSKP Singh 	private_key = PEM_read_bio_PrivateKey(b, NULL, NULL, NULL);
64*40863f4dSKP Singh 	BIO_free(b);
65*40863f4dSKP Singh 	DISPLAY_OSSL_ERR(!private_key);
66*40863f4dSKP Singh 	return private_key;
67*40863f4dSKP Singh }
68*40863f4dSKP Singh 
69*40863f4dSKP Singh static X509 *read_x509(const char *x509_name)
70*40863f4dSKP Singh {
71*40863f4dSKP Singh 	unsigned char buf[2];
72*40863f4dSKP Singh 	X509 *x509 = NULL;
73*40863f4dSKP Singh 	BIO *b;
74*40863f4dSKP Singh 	int n;
75*40863f4dSKP Singh 
76*40863f4dSKP Singh 	b = BIO_new_file(x509_name, "rb");
77*40863f4dSKP Singh 	if (!b)
78*40863f4dSKP Singh 		goto cleanup;
79*40863f4dSKP Singh 
80*40863f4dSKP Singh 	/* Look at the first two bytes of the file to determine the encoding */
81*40863f4dSKP Singh 	n = BIO_read(b, buf, 2);
82*40863f4dSKP Singh 	if (n != 2)
83*40863f4dSKP Singh 		goto cleanup;
84*40863f4dSKP Singh 
85*40863f4dSKP Singh 	if (BIO_reset(b) != 0)
86*40863f4dSKP Singh 		goto cleanup;
87*40863f4dSKP Singh 
88*40863f4dSKP Singh 	if (buf[0] == 0x30 && buf[1] >= 0x81 && buf[1] <= 0x84)
89*40863f4dSKP Singh 		/* Assume raw DER encoded X.509 */
90*40863f4dSKP Singh 		x509 = d2i_X509_bio(b, NULL);
91*40863f4dSKP Singh 	else
92*40863f4dSKP Singh 		/* Assume PEM encoded X.509 */
93*40863f4dSKP Singh 		x509 = PEM_read_bio_X509(b, NULL, NULL, NULL);
94*40863f4dSKP Singh 
95*40863f4dSKP Singh cleanup:
96*40863f4dSKP Singh 	BIO_free(b);
97*40863f4dSKP Singh 	DISPLAY_OSSL_ERR(!x509);
98*40863f4dSKP Singh 	return x509;
99*40863f4dSKP Singh }
100*40863f4dSKP Singh 
101*40863f4dSKP Singh __u32 register_session_key(const char *key_der_path)
102*40863f4dSKP Singh {
103*40863f4dSKP Singh 	unsigned char *der_buf = NULL;
104*40863f4dSKP Singh 	X509 *x509 = NULL;
105*40863f4dSKP Singh 	int key_id = -1;
106*40863f4dSKP Singh 	int der_len;
107*40863f4dSKP Singh 
108*40863f4dSKP Singh 	if (!key_der_path)
109*40863f4dSKP Singh 		return key_id;
110*40863f4dSKP Singh 	x509 = read_x509(key_der_path);
111*40863f4dSKP Singh 	if (!x509)
112*40863f4dSKP Singh 		goto cleanup;
113*40863f4dSKP Singh 	der_len = i2d_X509(x509, &der_buf);
114*40863f4dSKP Singh 	if (der_len < 0)
115*40863f4dSKP Singh 		goto cleanup;
116*40863f4dSKP Singh 	key_id = syscall(__NR_add_key, "asymmetric", key_der_path, der_buf,
117*40863f4dSKP Singh 			     (size_t)der_len, KEY_SPEC_SESSION_KEYRING);
118*40863f4dSKP Singh cleanup:
119*40863f4dSKP Singh 	X509_free(x509);
120*40863f4dSKP Singh 	OPENSSL_free(der_buf);
121*40863f4dSKP Singh 	DISPLAY_OSSL_ERR(key_id == -1);
122*40863f4dSKP Singh 	return key_id;
123*40863f4dSKP Singh }
124*40863f4dSKP Singh 
125*40863f4dSKP Singh int bpftool_prog_sign(struct bpf_load_and_run_opts *opts)
126*40863f4dSKP Singh {
127*40863f4dSKP Singh 	BIO *bd_in = NULL, *bd_out = NULL;
128*40863f4dSKP Singh 	EVP_PKEY *private_key = NULL;
129*40863f4dSKP Singh 	CMS_ContentInfo *cms = NULL;
130*40863f4dSKP Singh 	long actual_sig_len = 0;
131*40863f4dSKP Singh 	X509 *x509 = NULL;
132*40863f4dSKP Singh 	int err = 0;
133*40863f4dSKP Singh 
134*40863f4dSKP Singh 	bd_in = BIO_new_mem_buf(opts->insns, opts->insns_sz);
135*40863f4dSKP Singh 	if (!bd_in) {
136*40863f4dSKP Singh 		err = -ENOMEM;
137*40863f4dSKP Singh 		goto cleanup;
138*40863f4dSKP Singh 	}
139*40863f4dSKP Singh 
140*40863f4dSKP Singh 	private_key = read_private_key(private_key_path);
141*40863f4dSKP Singh 	if (!private_key) {
142*40863f4dSKP Singh 		err = -EINVAL;
143*40863f4dSKP Singh 		goto cleanup;
144*40863f4dSKP Singh 	}
145*40863f4dSKP Singh 
146*40863f4dSKP Singh 	x509 = read_x509(cert_path);
147*40863f4dSKP Singh 	if (!x509) {
148*40863f4dSKP Singh 		err = -EINVAL;
149*40863f4dSKP Singh 		goto cleanup;
150*40863f4dSKP Singh 	}
151*40863f4dSKP Singh 
152*40863f4dSKP Singh 	cms = CMS_sign(NULL, NULL, NULL, NULL,
153*40863f4dSKP Singh 		       CMS_NOCERTS | CMS_PARTIAL | CMS_BINARY | CMS_DETACHED |
154*40863f4dSKP Singh 			       CMS_STREAM);
155*40863f4dSKP Singh 	if (!cms) {
156*40863f4dSKP Singh 		err = -EINVAL;
157*40863f4dSKP Singh 		goto cleanup;
158*40863f4dSKP Singh 	}
159*40863f4dSKP Singh 
160*40863f4dSKP Singh 	if (!CMS_add1_signer(cms, x509, private_key, EVP_sha256(),
161*40863f4dSKP Singh 			     CMS_NOCERTS | CMS_BINARY | CMS_NOSMIMECAP |
162*40863f4dSKP Singh 			     CMS_USE_KEYID | CMS_NOATTR)) {
163*40863f4dSKP Singh 		err = -EINVAL;
164*40863f4dSKP Singh 		goto cleanup;
165*40863f4dSKP Singh 	}
166*40863f4dSKP Singh 
167*40863f4dSKP Singh 	if (CMS_final(cms, bd_in, NULL, CMS_NOCERTS | CMS_BINARY) != 1) {
168*40863f4dSKP Singh 		err = -EIO;
169*40863f4dSKP Singh 		goto cleanup;
170*40863f4dSKP Singh 	}
171*40863f4dSKP Singh 
172*40863f4dSKP Singh 	EVP_Digest(opts->insns, opts->insns_sz, opts->excl_prog_hash,
173*40863f4dSKP Singh 		   &opts->excl_prog_hash_sz, EVP_sha256(), NULL);
174*40863f4dSKP Singh 
175*40863f4dSKP Singh 		bd_out = BIO_new(BIO_s_mem());
176*40863f4dSKP Singh 	if (!bd_out) {
177*40863f4dSKP Singh 		err = -ENOMEM;
178*40863f4dSKP Singh 		goto cleanup;
179*40863f4dSKP Singh 	}
180*40863f4dSKP Singh 
181*40863f4dSKP Singh 	if (!i2d_CMS_bio_stream(bd_out, cms, NULL, 0)) {
182*40863f4dSKP Singh 		err = -EIO;
183*40863f4dSKP Singh 		goto cleanup;
184*40863f4dSKP Singh 	}
185*40863f4dSKP Singh 
186*40863f4dSKP Singh 	actual_sig_len = BIO_get_mem_data(bd_out, NULL);
187*40863f4dSKP Singh 	if (actual_sig_len <= 0) {
188*40863f4dSKP Singh 		err = -EIO;
189*40863f4dSKP Singh 		goto cleanup;
190*40863f4dSKP Singh 	}
191*40863f4dSKP Singh 
192*40863f4dSKP Singh 	if ((size_t)actual_sig_len > opts->signature_sz) {
193*40863f4dSKP Singh 		err = -ENOSPC;
194*40863f4dSKP Singh 		goto cleanup;
195*40863f4dSKP Singh 	}
196*40863f4dSKP Singh 
197*40863f4dSKP Singh 	if (BIO_read(bd_out, opts->signature, actual_sig_len) != actual_sig_len) {
198*40863f4dSKP Singh 		err = -EIO;
199*40863f4dSKP Singh 		goto cleanup;
200*40863f4dSKP Singh 	}
201*40863f4dSKP Singh 
202*40863f4dSKP Singh 	opts->signature_sz = actual_sig_len;
203*40863f4dSKP Singh cleanup:
204*40863f4dSKP Singh 	BIO_free(bd_out);
205*40863f4dSKP Singh 	CMS_ContentInfo_free(cms);
206*40863f4dSKP Singh 	X509_free(x509);
207*40863f4dSKP Singh 	EVP_PKEY_free(private_key);
208*40863f4dSKP Singh 	BIO_free(bd_in);
209*40863f4dSKP Singh 	DISPLAY_OSSL_ERR(err < 0);
210*40863f4dSKP Singh 	return err;
211*40863f4dSKP Singh }
212