Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/bpf/bpftool/sign.c
29267 views
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
static void display_openssl_errors(int l)
32
{
33
char buf[OPEN_SSL_ERR_BUF_LEN];
34
const char *file;
35
const char *data;
36
unsigned long e;
37
int flags;
38
int line;
39
40
while ((e = ERR_get_error_all(&file, &line, NULL, &data, &flags))) {
41
ERR_error_string_n(e, buf, sizeof(buf));
42
if (data && (flags & ERR_TXT_STRING)) {
43
p_err("OpenSSL %s: %s:%d: %s", buf, file, line, data);
44
} else {
45
p_err("OpenSSL %s: %s:%d", buf, file, line);
46
}
47
}
48
}
49
50
#define DISPLAY_OSSL_ERR(cond) \
51
do { \
52
bool __cond = (cond); \
53
if (__cond && ERR_peek_error()) \
54
display_openssl_errors(__LINE__);\
55
} while (0)
56
57
static EVP_PKEY *read_private_key(const char *pkey_path)
58
{
59
EVP_PKEY *private_key = NULL;
60
BIO *b;
61
62
b = BIO_new_file(pkey_path, "rb");
63
private_key = PEM_read_bio_PrivateKey(b, NULL, NULL, NULL);
64
BIO_free(b);
65
DISPLAY_OSSL_ERR(!private_key);
66
return private_key;
67
}
68
69
static X509 *read_x509(const char *x509_name)
70
{
71
unsigned char buf[2];
72
X509 *x509 = NULL;
73
BIO *b;
74
int n;
75
76
b = BIO_new_file(x509_name, "rb");
77
if (!b)
78
goto cleanup;
79
80
/* Look at the first two bytes of the file to determine the encoding */
81
n = BIO_read(b, buf, 2);
82
if (n != 2)
83
goto cleanup;
84
85
if (BIO_reset(b) != 0)
86
goto cleanup;
87
88
if (buf[0] == 0x30 && buf[1] >= 0x81 && buf[1] <= 0x84)
89
/* Assume raw DER encoded X.509 */
90
x509 = d2i_X509_bio(b, NULL);
91
else
92
/* Assume PEM encoded X.509 */
93
x509 = PEM_read_bio_X509(b, NULL, NULL, NULL);
94
95
cleanup:
96
BIO_free(b);
97
DISPLAY_OSSL_ERR(!x509);
98
return x509;
99
}
100
101
__u32 register_session_key(const char *key_der_path)
102
{
103
unsigned char *der_buf = NULL;
104
X509 *x509 = NULL;
105
int key_id = -1;
106
int der_len;
107
108
if (!key_der_path)
109
return key_id;
110
x509 = read_x509(key_der_path);
111
if (!x509)
112
goto cleanup;
113
der_len = i2d_X509(x509, &der_buf);
114
if (der_len < 0)
115
goto cleanup;
116
key_id = syscall(__NR_add_key, "asymmetric", key_der_path, der_buf,
117
(size_t)der_len, KEY_SPEC_SESSION_KEYRING);
118
cleanup:
119
X509_free(x509);
120
OPENSSL_free(der_buf);
121
DISPLAY_OSSL_ERR(key_id == -1);
122
return key_id;
123
}
124
125
int bpftool_prog_sign(struct bpf_load_and_run_opts *opts)
126
{
127
BIO *bd_in = NULL, *bd_out = NULL;
128
EVP_PKEY *private_key = NULL;
129
CMS_ContentInfo *cms = NULL;
130
long actual_sig_len = 0;
131
X509 *x509 = NULL;
132
int err = 0;
133
134
bd_in = BIO_new_mem_buf(opts->insns, opts->insns_sz);
135
if (!bd_in) {
136
err = -ENOMEM;
137
goto cleanup;
138
}
139
140
private_key = read_private_key(private_key_path);
141
if (!private_key) {
142
err = -EINVAL;
143
goto cleanup;
144
}
145
146
x509 = read_x509(cert_path);
147
if (!x509) {
148
err = -EINVAL;
149
goto cleanup;
150
}
151
152
cms = CMS_sign(NULL, NULL, NULL, NULL,
153
CMS_NOCERTS | CMS_PARTIAL | CMS_BINARY | CMS_DETACHED |
154
CMS_STREAM);
155
if (!cms) {
156
err = -EINVAL;
157
goto cleanup;
158
}
159
160
if (!CMS_add1_signer(cms, x509, private_key, EVP_sha256(),
161
CMS_NOCERTS | CMS_BINARY | CMS_NOSMIMECAP |
162
CMS_USE_KEYID | CMS_NOATTR)) {
163
err = -EINVAL;
164
goto cleanup;
165
}
166
167
if (CMS_final(cms, bd_in, NULL, CMS_NOCERTS | CMS_BINARY) != 1) {
168
err = -EIO;
169
goto cleanup;
170
}
171
172
EVP_Digest(opts->insns, opts->insns_sz, opts->excl_prog_hash,
173
&opts->excl_prog_hash_sz, EVP_sha256(), NULL);
174
175
bd_out = BIO_new(BIO_s_mem());
176
if (!bd_out) {
177
err = -ENOMEM;
178
goto cleanup;
179
}
180
181
if (!i2d_CMS_bio_stream(bd_out, cms, NULL, 0)) {
182
err = -EIO;
183
goto cleanup;
184
}
185
186
actual_sig_len = BIO_get_mem_data(bd_out, NULL);
187
if (actual_sig_len <= 0) {
188
err = -EIO;
189
goto cleanup;
190
}
191
192
if ((size_t)actual_sig_len > opts->signature_sz) {
193
err = -ENOSPC;
194
goto cleanup;
195
}
196
197
if (BIO_read(bd_out, opts->signature, actual_sig_len) != actual_sig_len) {
198
err = -EIO;
199
goto cleanup;
200
}
201
202
opts->signature_sz = actual_sig_len;
203
cleanup:
204
BIO_free(bd_out);
205
CMS_ContentInfo_free(cms);
206
X509_free(x509);
207
EVP_PKEY_free(private_key);
208
BIO_free(bd_in);
209
DISPLAY_OSSL_ERR(err < 0);
210
return err;
211
}
212
213