]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - fs/crypto/fscrypt_private.h
Merge tag 'devicetree-for-5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/robh...
[linux.git] / fs / crypto / fscrypt_private.h
index 9556e9499dc59c43b6325c38ade11f4e4149628e..e84efc01512e4e5dbfc2eab7efaf83101022110c 100644 (file)
 
 #define FSCRYPT_MIN_KEY_SIZE           16
 
-/**
- * Encryption context for inode
- *
- * Protector format:
- *  1 byte: Protector format (1 = this version)
- *  1 byte: File contents encryption mode
- *  1 byte: File names encryption mode
- *  1 byte: Flags
- *  8 bytes: Master Key descriptor
- *  16 bytes: Encryption Key derivation nonce
- */
-struct fscrypt_context {
-       u8 format;
+#define FSCRYPT_CONTEXT_V1     1
+#define FSCRYPT_CONTEXT_V2     2
+
+struct fscrypt_context_v1 {
+       u8 version; /* FSCRYPT_CONTEXT_V1 */
        u8 contents_encryption_mode;
        u8 filenames_encryption_mode;
        u8 flags;
        u8 master_key_descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE];
        u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE];
-} __packed;
+};
 
-#define FS_ENCRYPTION_CONTEXT_FORMAT_V1                1
+struct fscrypt_context_v2 {
+       u8 version; /* FSCRYPT_CONTEXT_V2 */
+       u8 contents_encryption_mode;
+       u8 filenames_encryption_mode;
+       u8 flags;
+       u8 __reserved[4];
+       u8 master_key_identifier[FSCRYPT_KEY_IDENTIFIER_SIZE];
+       u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE];
+};
+
+/**
+ * fscrypt_context - the encryption context of an inode
+ *
+ * This is the on-disk equivalent of an fscrypt_policy, stored alongside each
+ * encrypted file usually in a hidden extended attribute.  It contains the
+ * fields from the fscrypt_policy, in order to identify the encryption algorithm
+ * and key with which the file is encrypted.  It also contains a nonce that was
+ * randomly generated by fscrypt itself; this is used as KDF input or as a tweak
+ * to cause different files to be encrypted differently.
+ */
+union fscrypt_context {
+       u8 version;
+       struct fscrypt_context_v1 v1;
+       struct fscrypt_context_v2 v2;
+};
+
+/*
+ * Return the size expected for the given fscrypt_context based on its version
+ * number, or 0 if the context version is unrecognized.
+ */
+static inline int fscrypt_context_size(const union fscrypt_context *ctx)
+{
+       switch (ctx->version) {
+       case FSCRYPT_CONTEXT_V1:
+               BUILD_BUG_ON(sizeof(ctx->v1) != 28);
+               return sizeof(ctx->v1);
+       case FSCRYPT_CONTEXT_V2:
+               BUILD_BUG_ON(sizeof(ctx->v2) != 40);
+               return sizeof(ctx->v2);
+       }
+       return 0;
+}
+
+#undef fscrypt_policy
+union fscrypt_policy {
+       u8 version;
+       struct fscrypt_policy_v1 v1;
+       struct fscrypt_policy_v2 v2;
+};
+
+/*
+ * Return the size expected for the given fscrypt_policy based on its version
+ * number, or 0 if the policy version is unrecognized.
+ */
+static inline int fscrypt_policy_size(const union fscrypt_policy *policy)
+{
+       switch (policy->version) {
+       case FSCRYPT_POLICY_V1:
+               return sizeof(policy->v1);
+       case FSCRYPT_POLICY_V2:
+               return sizeof(policy->v2);
+       }
+       return 0;
+}
+
+/* Return the contents encryption mode of a valid encryption policy */
+static inline u8
+fscrypt_policy_contents_mode(const union fscrypt_policy *policy)
+{
+       switch (policy->version) {
+       case FSCRYPT_POLICY_V1:
+               return policy->v1.contents_encryption_mode;
+       case FSCRYPT_POLICY_V2:
+               return policy->v2.contents_encryption_mode;
+       }
+       BUG();
+}
+
+/* Return the filenames encryption mode of a valid encryption policy */
+static inline u8
+fscrypt_policy_fnames_mode(const union fscrypt_policy *policy)
+{
+       switch (policy->version) {
+       case FSCRYPT_POLICY_V1:
+               return policy->v1.filenames_encryption_mode;
+       case FSCRYPT_POLICY_V2:
+               return policy->v2.filenames_encryption_mode;
+       }
+       BUG();
+}
+
+/* Return the flags (FSCRYPT_POLICY_FLAG*) of a valid encryption policy */
+static inline u8
+fscrypt_policy_flags(const union fscrypt_policy *policy)
+{
+       switch (policy->version) {
+       case FSCRYPT_POLICY_V1:
+               return policy->v1.flags;
+       case FSCRYPT_POLICY_V2:
+               return policy->v2.flags;
+       }
+       BUG();
+}
+
+static inline bool
+fscrypt_is_direct_key_policy(const union fscrypt_policy *policy)
+{
+       return fscrypt_policy_flags(policy) & FSCRYPT_POLICY_FLAG_DIRECT_KEY;
+}
 
 /**
  * For encrypted symlinks, the ciphertext length is stored at the beginning
@@ -70,8 +170,8 @@ struct fscrypt_info {
        struct crypto_cipher *ci_essiv_tfm;
 
        /*
-        * Encryption mode used for this inode.  It corresponds to either
-        * ci_data_mode or ci_filename_mode, depending on the inode type.
+        * Encryption mode used for this inode.  It corresponds to either the
+        * contents or filenames encryption mode, depending on the inode type.
         */
        struct fscrypt_mode *ci_mode;
 
@@ -97,11 +197,10 @@ struct fscrypt_info {
         */
        struct fscrypt_direct_key *ci_direct_key;
 
-       /* fields from the fscrypt_context */
-       u8 ci_data_mode;
-       u8 ci_filename_mode;
-       u8 ci_flags;
-       u8 ci_master_key_descriptor[FSCRYPT_KEY_DESCRIPTOR_SIZE];
+       /* The encryption policy used by this inode */
+       union fscrypt_policy ci_policy;
+
+       /* This inode's nonce, copied from the fscrypt_context */
        u8 ci_nonce[FS_KEY_DERIVATION_NONCE_SIZE];
 };
 
@@ -181,6 +280,17 @@ struct fscrypt_hkdf {
 extern int fscrypt_init_hkdf(struct fscrypt_hkdf *hkdf, const u8 *master_key,
                             unsigned int master_key_size);
 
+/*
+ * The list of contexts in which fscrypt uses HKDF.  These values are used as
+ * the first byte of the HKDF application-specific info string to guarantee that
+ * info strings are never repeated between contexts.  This ensures that all HKDF
+ * outputs are unique and cryptographically isolated, i.e. knowledge of one
+ * output doesn't reveal another.
+ */
+#define HKDF_CONTEXT_KEY_IDENTIFIER    1
+#define HKDF_CONTEXT_PER_FILE_KEY      2
+#define HKDF_CONTEXT_PER_MODE_KEY      3
+
 extern int fscrypt_hkdf_expand(struct fscrypt_hkdf *hkdf, u8 context,
                               const u8 *info, unsigned int infolen,
                               u8 *okm, unsigned int okmlen);
@@ -194,10 +304,16 @@ extern void fscrypt_destroy_hkdf(struct fscrypt_hkdf *hkdf);
  */
 struct fscrypt_master_key_secret {
 
-       /* Size of the raw key in bytes */
+       /*
+        * For v2 policy keys: HKDF context keyed by this master key.
+        * For v1 policy keys: not set (hkdf.hmac_tfm == NULL).
+        */
+       struct fscrypt_hkdf     hkdf;
+
+       /* Size of the raw key in bytes.  Set even if ->raw isn't set. */
        u32                     size;
 
-       /* The raw key */
+       /* For v1 policy keys: the raw key.  Wiped for v2 policy keys. */
        u8                      raw[FSCRYPT_MAX_KEY_SIZE];
 
 } __randomize_layout;
@@ -219,13 +335,41 @@ struct fscrypt_master_key {
         * FS_IOC_REMOVE_ENCRYPTION_KEY can be retried, or
         * FS_IOC_ADD_ENCRYPTION_KEY can add the secret again.
         *
-        * Locking: protected by key->sem.
+        * Locking: protected by key->sem (outer) and mk_secret_sem (inner).
+        * The reason for two locks is that key->sem also protects modifying
+        * mk_users, which ranks it above the semaphore for the keyring key
+        * type, which is in turn above page faults (via keyring_read).  But
+        * sometimes filesystems call fscrypt_get_encryption_info() from within
+        * a transaction, which ranks it below page faults.  So we need a
+        * separate lock which protects mk_secret but not also mk_users.
         */
        struct fscrypt_master_key_secret        mk_secret;
+       struct rw_semaphore                     mk_secret_sem;
 
-       /* Arbitrary key descriptor which was assigned by userspace */
+       /*
+        * For v1 policy keys: an arbitrary key descriptor which was assigned by
+        * userspace (->descriptor).
+        *
+        * For v2 policy keys: a cryptographic hash of this key (->identifier).
+        */
        struct fscrypt_key_specifier            mk_spec;
 
+       /*
+        * Keyring which contains a key of type 'key_type_fscrypt_user' for each
+        * user who has added this key.  Normally each key will be added by just
+        * one user, but it's possible that multiple users share a key, and in
+        * that case we need to keep track of those users so that one user can't
+        * remove the key before the others want it removed too.
+        *
+        * This is NULL for v1 policy keys; those can only be added by root.
+        *
+        * Locking: in addition to this keyrings own semaphore, this is
+        * protected by the master key's key->sem, so we can do atomic
+        * search+insert.  It can also be searched without taking any locks, but
+        * in that case the returned key may have already been removed.
+        */
+       struct key              *mk_users;
+
        /*
         * Length of ->mk_decrypted_inodes, plus one if mk_secret is present.
         * Once this goes to 0, the master key is removed from ->s_master_keys.
@@ -242,6 +386,9 @@ struct fscrypt_master_key {
        struct list_head        mk_decrypted_inodes;
        spinlock_t              mk_decrypted_inodes_lock;
 
+       /* Per-mode tfms for DIRECT_KEY policies, allocated on-demand */
+       struct crypto_skcipher  *mk_mode_keys[__FSCRYPT_MODE_MAX + 1];
+
 } __randomize_layout;
 
 static inline bool
@@ -250,9 +397,9 @@ is_master_key_secret_present(const struct fscrypt_master_key_secret *secret)
        /*
         * The READ_ONCE() is only necessary for fscrypt_drop_inode() and
         * fscrypt_key_describe().  These run in atomic context, so they can't
-        * take key->sem and thus 'secret' can change concurrently which would
-        * be a data race.  But they only need to know whether the secret *was*
-        * present at the time of check, so READ_ONCE() suffices.
+        * take ->mk_secret_sem and thus 'secret' can change concurrently which
+        * would be a data race.  But they only need to know whether the secret
+        * *was* present at the time of check, so READ_ONCE() suffices.
         */
        return READ_ONCE(secret->size) != 0;
 }
@@ -263,6 +410,8 @@ static inline const char *master_key_spec_type(
        switch (spec->type) {
        case FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR:
                return "descriptor";
+       case FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER:
+               return "identifier";
        }
        return "[unknown]";
 }
@@ -272,6 +421,8 @@ static inline int master_key_spec_len(const struct fscrypt_key_specifier *spec)
        switch (spec->type) {
        case FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR:
                return FSCRYPT_KEY_DESCRIPTOR_SIZE;
+       case FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER:
+               return FSCRYPT_KEY_IDENTIFIER_SIZE;
        }
        return 0;
 }
@@ -280,6 +431,9 @@ extern struct key *
 fscrypt_find_master_key(struct super_block *sb,
                        const struct fscrypt_key_specifier *mk_spec);
 
+extern int fscrypt_verify_key_added(struct super_block *sb,
+                                   const u8 identifier[FSCRYPT_KEY_IDENTIFIER_SIZE]);
+
 extern int __init fscrypt_init_keyring(void);
 
 /* keysetup.c */
@@ -315,5 +469,14 @@ extern int fscrypt_setup_v1_file_key(struct fscrypt_info *ci,
 
 extern int fscrypt_setup_v1_file_key_via_subscribed_keyrings(
                                        struct fscrypt_info *ci);
+/* policy.c */
+
+extern bool fscrypt_policies_equal(const union fscrypt_policy *policy1,
+                                  const union fscrypt_policy *policy2);
+extern bool fscrypt_supported_policy(const union fscrypt_policy *policy_u,
+                                    const struct inode *inode);
+extern int fscrypt_policy_from_context(union fscrypt_policy *policy_u,
+                                      const union fscrypt_context *ctx_u,
+                                      int ctx_size);
 
 #endif /* _FSCRYPT_PRIVATE_H */