1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include "errno-util.h"
7 #include "homectl-pkcs11.h"
8 #include "libcrypt-util.h"
10 #include "openssl-util.h"
11 #include "pkcs11-util.h"
12 #include "string-util.h"
15 int identity_add_token_pin(sd_json_variant
**v
, const char *pin
) {
16 _cleanup_(sd_json_variant_unrefp
) sd_json_variant
*w
= NULL
, *l
= NULL
;
17 _cleanup_strv_free_erase_
char **pins
= NULL
;
25 w
= sd_json_variant_ref(sd_json_variant_by_key(*v
, "secret"));
26 l
= sd_json_variant_ref(sd_json_variant_by_key(w
, "tokenPin"));
28 r
= sd_json_variant_strv(l
, &pins
);
30 return log_error_errno(r
, "Failed to convert PIN array: %m");
32 if (strv_contains(pins
, pin
))
35 r
= strv_extend(&pins
, pin
);
41 l
= sd_json_variant_unref(l
);
43 r
= sd_json_variant_new_array_strv(&l
, pins
);
45 return log_error_errno(r
, "Failed to allocate new PIN array JSON: %m");
47 sd_json_variant_sensitive(l
);
49 r
= sd_json_variant_set_field(&w
, "tokenPin", l
);
51 return log_error_errno(r
, "Failed to update PIN field: %m");
53 sd_json_variant_sensitive(w
);
55 r
= sd_json_variant_set_field(v
, "secret", w
);
57 return log_error_errno(r
, "Failed to update secret object: %m");
64 static int add_pkcs11_token_uri(sd_json_variant
**v
, const char *uri
) {
65 _cleanup_(sd_json_variant_unrefp
) sd_json_variant
*w
= NULL
;
66 _cleanup_strv_free_
char **l
= NULL
;
72 w
= sd_json_variant_ref(sd_json_variant_by_key(*v
, "pkcs11TokenUri"));
74 r
= sd_json_variant_strv(w
, &l
);
76 return log_error_errno(r
, "Failed to parse PKCS#11 token list: %m");
78 if (strv_contains(l
, uri
))
82 r
= strv_extend(&l
, uri
);
86 w
= sd_json_variant_unref(w
);
87 r
= sd_json_variant_new_array_strv(&w
, l
);
89 return log_error_errno(r
, "Failed to create PKCS#11 token URI JSON: %m");
91 r
= sd_json_variant_set_field(v
, "pkcs11TokenUri", w
);
93 return log_error_errno(r
, "Failed to update PKCS#11 token URI list: %m");
98 static int add_pkcs11_encrypted_key(
101 const void *encrypted_key
, size_t encrypted_key_size
,
102 const void *decrypted_key
, size_t decrypted_key_size
) {
104 _cleanup_(sd_json_variant_unrefp
) sd_json_variant
*l
= NULL
, *w
= NULL
, *e
= NULL
;
105 _cleanup_(erase_and_freep
) char *base64_encoded
= NULL
, *hashed
= NULL
;
106 ssize_t base64_encoded_size
;
111 assert(encrypted_key
);
112 assert(encrypted_key_size
> 0);
113 assert(decrypted_key
);
114 assert(decrypted_key_size
> 0);
116 /* Before using UNIX hashing on the supplied key we base64 encode it, since crypt_r() and friends
117 * expect a NUL terminated string, and we use a binary key */
118 base64_encoded_size
= base64mem(decrypted_key
, decrypted_key_size
, &base64_encoded
);
119 if (base64_encoded_size
< 0)
120 return log_error_errno(base64_encoded_size
, "Failed to base64 encode secret key: %m");
122 r
= hash_password(base64_encoded
, &hashed
);
124 return log_error_errno(errno_or_else(EINVAL
), "Failed to UNIX hash secret key: %m");
126 r
= sd_json_buildo(&e
,
127 SD_JSON_BUILD_PAIR("uri", SD_JSON_BUILD_STRING(uri
)),
128 SD_JSON_BUILD_PAIR("data", SD_JSON_BUILD_BASE64(encrypted_key
, encrypted_key_size
)),
129 SD_JSON_BUILD_PAIR("hashedPassword", SD_JSON_BUILD_STRING(hashed
)));
131 return log_error_errno(r
, "Failed to build encrypted JSON key object: %m");
133 w
= sd_json_variant_ref(sd_json_variant_by_key(*v
, "privileged"));
134 l
= sd_json_variant_ref(sd_json_variant_by_key(w
, "pkcs11EncryptedKey"));
136 r
= sd_json_variant_append_array(&l
, e
);
138 return log_error_errno(r
, "Failed append PKCS#11 encrypted key: %m");
140 r
= sd_json_variant_set_field(&w
, "pkcs11EncryptedKey", l
);
142 return log_error_errno(r
, "Failed to set PKCS#11 encrypted key: %m");
144 r
= sd_json_variant_set_field(v
, "privileged", w
);
146 return log_error_errno(r
, "Failed to update privileged field: %m");
153 int identity_add_pkcs11_key_data(sd_json_variant
**v
, const char *uri
) {
155 _cleanup_(erase_and_freep
) void *decrypted_key
= NULL
, *saved_key
= NULL
;
156 _cleanup_(erase_and_freep
) char *pin
= NULL
;
157 size_t decrypted_key_size
, saved_key_size
;
158 _cleanup_(EVP_PKEY_freep
) EVP_PKEY
*pkey
= NULL
;
163 r
= pkcs11_acquire_public_key(
165 "home directory operation",
168 /* askpw_flags= */ 0,
174 r
= pkey_generate_volume_keys(pkey
, &decrypted_key
, &decrypted_key_size
, &saved_key
, &saved_key_size
);
176 return log_error_errno(r
, "Failed to generate volume keys: %m");
178 /* Add the token URI to the public part of the record. */
179 r
= add_pkcs11_token_uri(v
, uri
);
183 /* Include the encrypted version of the random key we just generated in the privileged part of the record */
184 r
= add_pkcs11_encrypted_key(
187 saved_key
, saved_key_size
,
188 decrypted_key
, decrypted_key_size
);
192 /* If we acquired the PIN also include it in the secret section of the record, so that systemd-homed
193 * can use it if it needs to, given that it likely needs to decrypt the key again to pass to LUKS or
195 r
= identity_add_token_pin(v
, pin
);
201 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "PKCS#11 tokens not supported on this build.");