1 #include <openssl/pem.h>
4 #include "user-record-sign.h"
7 static int user_record_signable_json(UserRecord
*ur
, char **ret
) {
8 _cleanup_(user_record_unrefp
) UserRecord
*reduced
= NULL
;
9 _cleanup_(json_variant_unrefp
) JsonVariant
*j
= NULL
;
15 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
, &reduced
);
19 j
= json_variant_ref(reduced
->json
);
21 r
= json_variant_normalize(&j
);
25 return json_variant_format(j
, 0, ret
);
28 DEFINE_TRIVIAL_CLEANUP_FUNC(EVP_MD_CTX
*, EVP_MD_CTX_free
);
30 int user_record_sign(UserRecord
*ur
, EVP_PKEY
*private_key
, UserRecord
**ret
) {
31 _cleanup_(json_variant_unrefp
) JsonVariant
*encoded
= NULL
, *v
= NULL
;
32 _cleanup_(user_record_unrefp
) UserRecord
*signed_ur
= NULL
;
33 _cleanup_(EVP_MD_CTX_freep
) EVP_MD_CTX
*md_ctx
= NULL
;
34 _cleanup_free_
char *text
= NULL
, *key
= NULL
;
35 size_t signature_size
= 0, key_size
= 0;
36 _cleanup_free_
void *signature
= NULL
;
37 _cleanup_fclose_
FILE *mf
= NULL
;
44 r
= user_record_signable_json(ur
, &text
);
48 md_ctx
= EVP_MD_CTX_new();
52 if (EVP_DigestSignInit(md_ctx
, NULL
, NULL
, NULL
, private_key
) <= 0)
55 /* Request signature size */
56 if (EVP_DigestSign(md_ctx
, NULL
, &signature_size
, (uint8_t*) text
, strlen(text
)) <= 0)
59 signature
= malloc(signature_size
);
63 if (EVP_DigestSign(md_ctx
, signature
, &signature_size
, (uint8_t*) text
, strlen(text
)) <= 0)
66 mf
= open_memstream_unlocked(&key
, &key_size
);
70 if (PEM_write_PUBKEY(mf
, private_key
) <= 0)
73 r
= fflush_and_check(mf
);
77 r
= json_build(&encoded
, JSON_BUILD_ARRAY(
78 JSON_BUILD_OBJECT(JSON_BUILD_PAIR("data", JSON_BUILD_BASE64(signature
, signature_size
)),
79 JSON_BUILD_PAIR("key", JSON_BUILD_STRING(key
)))));
83 v
= json_variant_ref(ur
->json
);
85 r
= json_variant_set_field(&v
, "signature", encoded
);
90 json_variant_dump(v
, JSON_FORMAT_PRETTY
|JSON_FORMAT_COLOR_AUTO
, NULL
, NULL
);
92 signed_ur
= user_record_new();
96 r
= user_record_load(signed_ur
, v
, USER_RECORD_LOAD_FULL
);
100 *ret
= TAKE_PTR(signed_ur
);
104 int user_record_verify(UserRecord
*ur
, EVP_PKEY
*public_key
) {
105 _cleanup_free_
char *text
= NULL
;
106 unsigned n_good
= 0, n_bad
= 0;
107 JsonVariant
*array
, *e
;
113 array
= json_variant_by_key(ur
->json
, "signature");
115 return USER_RECORD_UNSIGNED
;
117 if (!json_variant_is_array(array
))
120 if (json_variant_elements(array
) == 0)
121 return USER_RECORD_UNSIGNED
;
123 r
= user_record_signable_json(ur
, &text
);
127 JSON_VARIANT_ARRAY_FOREACH(e
, array
) {
128 _cleanup_(EVP_MD_CTX_freep
) EVP_MD_CTX
*md_ctx
= NULL
;
129 _cleanup_free_
void *signature
= NULL
;
130 size_t signature_size
= 0;
133 if (!json_variant_is_object(e
))
136 data
= json_variant_by_key(e
, "data");
140 r
= json_variant_unbase64(data
, &signature
, &signature_size
);
144 md_ctx
= EVP_MD_CTX_new();
148 if (EVP_DigestVerifyInit(md_ctx
, NULL
, NULL
, NULL
, public_key
) <= 0)
151 if (EVP_DigestVerify(md_ctx
, signature
, signature_size
, (uint8_t*) text
, strlen(text
)) <= 0) {
159 return n_good
> 0 ? (n_bad
== 0 ? USER_RECORD_SIGNED_EXCLUSIVE
: USER_RECORD_SIGNED
) :
160 (n_bad
== 0 ? USER_RECORD_UNSIGNED
: USER_RECORD_FOREIGN
);
163 int user_record_has_signature(UserRecord
*ur
) {
166 array
= json_variant_by_key(ur
->json
, "signature");
170 if (!json_variant_is_array(array
))
173 return json_variant_elements(array
) > 0;