1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "alloc-util.h"
6 #include "openssl-util.h"
7 #include "user-record-sign.h"
8 #include "user-record.h"
10 static int user_record_signable_json(UserRecord
*ur
, char **ret
) {
11 _cleanup_(user_record_unrefp
) UserRecord
*reduced
= NULL
;
12 _cleanup_(sd_json_variant_unrefp
) sd_json_variant
*j
= NULL
;
18 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
);
22 j
= sd_json_variant_ref(reduced
->json
);
24 r
= sd_json_variant_normalize(&j
);
28 return sd_json_variant_format(j
, 0, ret
);
31 int user_record_sign(UserRecord
*ur
, EVP_PKEY
*private_key
, UserRecord
**ret
) {
32 _cleanup_(sd_json_variant_unrefp
) sd_json_variant
*v
= NULL
;
33 _cleanup_(user_record_unrefp
) UserRecord
*signed_ur
= NULL
;
34 _cleanup_free_
char *text
= NULL
, *key
= NULL
;
35 _cleanup_free_
void *signature
= NULL
;
36 size_t signature_size
= 0;
43 r
= user_record_signable_json(ur
, &text
);
47 r
= digest_and_sign(/* md= */ NULL
, private_key
, text
, SIZE_MAX
, &signature
, &signature_size
);
51 r
= openssl_pubkey_to_pem(private_key
, &key
);
55 v
= sd_json_variant_ref(ur
->json
);
57 r
= sd_json_variant_set_fieldb(
61 SD_JSON_BUILD_OBJECT(SD_JSON_BUILD_PAIR("data", SD_JSON_BUILD_BASE64(signature
, signature_size
)),
62 SD_JSON_BUILD_PAIR("key", SD_JSON_BUILD_STRING(key
)))));
67 sd_json_variant_dump(v
, SD_JSON_FORMAT_PRETTY
|SD_JSON_FORMAT_COLOR_AUTO
, NULL
, NULL
);
69 signed_ur
= user_record_new();
73 r
= user_record_load(signed_ur
, v
, USER_RECORD_LOAD_FULL
|USER_RECORD_PERMISSIVE
);
77 *ret
= TAKE_PTR(signed_ur
);
81 int user_record_verify(UserRecord
*ur
, EVP_PKEY
*public_key
) {
82 _cleanup_free_
char *text
= NULL
;
83 unsigned n_good
= 0, n_bad
= 0;
84 sd_json_variant
*array
, *e
;
90 array
= sd_json_variant_by_key(ur
->json
, "signature");
92 return USER_RECORD_UNSIGNED
;
94 if (!sd_json_variant_is_array(array
))
97 if (sd_json_variant_elements(array
) == 0)
98 return USER_RECORD_UNSIGNED
;
100 r
= user_record_signable_json(ur
, &text
);
104 JSON_VARIANT_ARRAY_FOREACH(e
, array
) {
105 _cleanup_(EVP_MD_CTX_freep
) EVP_MD_CTX
*md_ctx
= NULL
;
106 _cleanup_free_
void *signature
= NULL
;
107 size_t signature_size
= 0;
108 sd_json_variant
*data
;
110 if (!sd_json_variant_is_object(e
))
113 data
= sd_json_variant_by_key(e
, "data");
117 r
= sd_json_variant_unbase64(data
, &signature
, &signature_size
);
121 md_ctx
= EVP_MD_CTX_new();
125 if (EVP_DigestVerifyInit(md_ctx
, NULL
, NULL
, NULL
, public_key
) <= 0)
128 if (EVP_DigestVerify(md_ctx
, signature
, signature_size
, (uint8_t*) text
, strlen(text
)) <= 0) {
136 return n_good
> 0 ? (n_bad
== 0 ? USER_RECORD_SIGNED_EXCLUSIVE
: USER_RECORD_SIGNED
) :
137 (n_bad
== 0 ? USER_RECORD_UNSIGNED
: USER_RECORD_FOREIGN
);
140 int user_record_has_signature(UserRecord
*ur
) {
141 sd_json_variant
*array
;
143 array
= sd_json_variant_by_key(ur
->json
, "signature");
147 if (!sd_json_variant_is_array(array
))
150 return sd_json_variant_elements(array
) > 0;