]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/home/user-record-sign.c
tree-wide: drop space between variable and an increment/decrement
[thirdparty/systemd.git] / src / home / user-record-sign.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
4368277c 2
70a5db58
LP
3#include <openssl/pem.h>
4
5#include "fd-util.h"
8fc798a9 6#include "fileio.h"
2485b7e2 7#include "memstream-util.h"
8fc798a9 8#include "openssl-util.h"
70a5db58 9#include "user-record-sign.h"
70a5db58
LP
10
11static int user_record_signable_json(UserRecord *ur, char **ret) {
12 _cleanup_(user_record_unrefp) UserRecord *reduced = NULL;
13 _cleanup_(json_variant_unrefp) JsonVariant *j = NULL;
14 int r;
15
16 assert(ur);
17 assert(ret);
18
bfc0cc1a 19 r = user_record_clone(ur, USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_PRIVILEGED|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_STRIP_SECRET|USER_RECORD_STRIP_BINDING|USER_RECORD_STRIP_STATUS|USER_RECORD_STRIP_SIGNATURE|USER_RECORD_PERMISSIVE, &reduced);
70a5db58
LP
20 if (r < 0)
21 return r;
22
23 j = json_variant_ref(reduced->json);
24
25 r = json_variant_normalize(&j);
26 if (r < 0)
27 return r;
28
29 return json_variant_format(j, 0, ret);
30}
31
70a5db58 32int user_record_sign(UserRecord *ur, EVP_PKEY *private_key, UserRecord **ret) {
2485b7e2 33 _cleanup_(memstream_done) MemStream m = {};
f5fc7732 34 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
70a5db58 35 _cleanup_(user_record_unrefp) UserRecord *signed_ur = NULL;
70a5db58 36 _cleanup_free_ char *text = NULL, *key = NULL;
70a5db58 37 _cleanup_free_ void *signature = NULL;
2485b7e2
YW
38 size_t signature_size = 0;
39 FILE *f;
70a5db58
LP
40 int r;
41
42 assert(ur);
43 assert(private_key);
44 assert(ret);
45
46 r = user_record_signable_json(ur, &text);
47 if (r < 0)
48 return r;
49
ef65c0f6
LP
50 r = digest_and_sign(/* md= */ NULL, private_key, text, SIZE_MAX, &signature, &signature_size);
51 if (r < 0)
52 return r;
70a5db58 53
2485b7e2
YW
54 f = memstream_init(&m);
55 if (!f)
70a5db58
LP
56 return -ENOMEM;
57
2485b7e2 58 if (PEM_write_PUBKEY(f, private_key) <= 0)
70a5db58
LP
59 return -EIO;
60
2485b7e2 61 r = memstream_finalize(&m, &key, NULL);
70a5db58
LP
62 if (r < 0)
63 return r;
64
70a5db58
LP
65 v = json_variant_ref(ur->json);
66
f5fc7732
LP
67 r = json_variant_set_fieldb(
68 &v,
69 "signature",
70 JSON_BUILD_ARRAY(
71 JSON_BUILD_OBJECT(JSON_BUILD_PAIR("data", JSON_BUILD_BASE64(signature, signature_size)),
72 JSON_BUILD_PAIR("key", JSON_BUILD_STRING(key)))));
70a5db58
LP
73 if (r < 0)
74 return r;
75
76 if (DEBUG_LOGGING)
77 json_variant_dump(v, JSON_FORMAT_PRETTY|JSON_FORMAT_COLOR_AUTO, NULL, NULL);
78
79 signed_ur = user_record_new();
80 if (!signed_ur)
81 return log_oom();
82
bfc0cc1a 83 r = user_record_load(signed_ur, v, USER_RECORD_LOAD_FULL|USER_RECORD_PERMISSIVE);
70a5db58
LP
84 if (r < 0)
85 return r;
86
87 *ret = TAKE_PTR(signed_ur);
88 return 0;
89}
90
91int user_record_verify(UserRecord *ur, EVP_PKEY *public_key) {
92 _cleanup_free_ char *text = NULL;
93 unsigned n_good = 0, n_bad = 0;
94 JsonVariant *array, *e;
95 int r;
96
97 assert(ur);
98 assert(public_key);
99
100 array = json_variant_by_key(ur->json, "signature");
101 if (!array)
102 return USER_RECORD_UNSIGNED;
103
104 if (!json_variant_is_array(array))
105 return -EINVAL;
106
107 if (json_variant_elements(array) == 0)
108 return USER_RECORD_UNSIGNED;
109
110 r = user_record_signable_json(ur, &text);
111 if (r < 0)
112 return r;
113
114 JSON_VARIANT_ARRAY_FOREACH(e, array) {
115 _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX *md_ctx = NULL;
116 _cleanup_free_ void *signature = NULL;
117 size_t signature_size = 0;
118 JsonVariant *data;
119
120 if (!json_variant_is_object(e))
121 return -EINVAL;
122
123 data = json_variant_by_key(e, "data");
124 if (!data)
125 return -EINVAL;
126
127 r = json_variant_unbase64(data, &signature, &signature_size);
128 if (r < 0)
129 return r;
130
131 md_ctx = EVP_MD_CTX_new();
132 if (!md_ctx)
133 return -ENOMEM;
134
135 if (EVP_DigestVerifyInit(md_ctx, NULL, NULL, NULL, public_key) <= 0)
136 return -EIO;
137
138 if (EVP_DigestVerify(md_ctx, signature, signature_size, (uint8_t*) text, strlen(text)) <= 0) {
b3a9d980 139 n_bad++;
70a5db58
LP
140 continue;
141 }
142
b3a9d980 143 n_good++;
70a5db58
LP
144 }
145
146 return n_good > 0 ? (n_bad == 0 ? USER_RECORD_SIGNED_EXCLUSIVE : USER_RECORD_SIGNED) :
147 (n_bad == 0 ? USER_RECORD_UNSIGNED : USER_RECORD_FOREIGN);
148}
149
150int user_record_has_signature(UserRecord *ur) {
151 JsonVariant *array;
152
153 array = json_variant_by_key(ur->json, "signature");
154 if (!array)
155 return false;
156
157 if (!json_variant_is_array(array))
158 return -EINVAL;
159
160 return json_variant_elements(array) > 0;
161}