File Index
Files and directories
Sign in
FILE

sign.c

File preview with syntax highlighting.

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