Add verity uuid specification.
[platform/upstream/cryptsetup.git] / lib / setup.c
index 21053fd..bcd22df 100644 (file)
@@ -67,9 +67,9 @@ struct crypt_device {
 
        /* used in CRYPT_VERITY */
        struct crypt_params_verity verity_hdr;
-       uint32_t verity_flags;
        char *verity_root_hash;
        uint64_t verity_root_hash_size;
+       char *verity_uuid;
 
        /* callbacks definitions */
        void (*log)(int level, const char *msg, void *usrptr);
@@ -655,15 +655,19 @@ static int _crypt_load_verity(struct crypt_device *cd, struct crypt_params_verit
        if (r < 0)
                return r;
 
+       if (params->flags & CRYPT_VERITY_NO_HEADER)
+               return -EINVAL;
+
        if (params)
                sb_offset = params->hash_area_offset;
 
-       r = VERITY_read_sb(cd, mdata_device(cd), sb_offset, &cd->verity_hdr);
+       r = VERITY_read_sb(cd, mdata_device(cd), sb_offset,
+                          &cd->verity_uuid, &cd->verity_hdr);
        if (r < 0)
                return r;
 
        if (params)
-               cd->verity_flags = params->flags;
+               cd->verity_hdr.flags = params->flags;
 
        if (params && params->data_device &&
            (r = crypt_set_data_device(cd, params->data_device)) < 0)
@@ -763,20 +767,23 @@ static int _init_by_name_verity(struct crypt_device *cd, const char *name)
                goto out;
 
        if (isVERITY(cd->type)) {
-               cd->verity_flags = CRYPT_VERITY_NO_HEADER; //FIXME
-               //cd->verity_uuid = dmd.uuid ? strdup(dmd.uuid) : NULL;
+               cd->verity_uuid = dmd.uuid ? strdup(dmd.uuid) : NULL;
+               cd->verity_hdr.flags = CRYPT_VERITY_NO_HEADER; //FIXME
                cd->verity_hdr.data_size = params.data_size;
                cd->verity_root_hash_size = dmd.u.verity.root_hash_size;
                cd->verity_root_hash = NULL;
                cd->verity_hdr.hash_name = params.hash_name;
                cd->verity_hdr.data_device = NULL;
+               cd->verity_hdr.hash_device = NULL;
                cd->verity_hdr.data_block_size = params.data_block_size;
                cd->verity_hdr.hash_block_size = params.hash_block_size;
-               cd->verity_hdr.hash_area_offset = params.hash_area_offset;
-               cd->verity_hdr.version = params.version;
+               cd->verity_hdr.hash_area_offset = dmd.u.verity.hash_offset;
+               cd->verity_hdr.hash_type = params.hash_type;
                cd->verity_hdr.flags = params.flags;
                cd->verity_hdr.salt_size = params.salt_size;
                cd->verity_hdr.salt = params.salt;
+               if (!(cd->metadata_device = strdup(dmd.u.verity.hash_device)))
+                       r = -ENOMEM;
        }
 out:
        free(CONST_CAST(void*)dmd.u.verity.hash_device);
@@ -1018,6 +1025,7 @@ static int _crypt_format_loopaes(struct crypt_device *cd,
 }
 
 static int _crypt_format_verity(struct crypt_device *cd,
+                                const char *uuid,
                                 struct crypt_params_verity *params)
 {
        int r = 0;
@@ -1031,10 +1039,7 @@ static int _crypt_format_verity(struct crypt_device *cd,
        if (!params || !params->data_device)
                return -EINVAL;
 
-       if (params->version > 1)
-               return -EINVAL;
-
-       /* set dat device */
+       /* set data device */
        cd->type = CRYPT_VERITY;
        r = crypt_set_data_device(cd, params->data_device);
        cd->type = NULL;
@@ -1049,22 +1054,21 @@ static int _crypt_format_verity(struct crypt_device *cd,
        } else
                cd->verity_hdr.data_size = params->data_size;
 
-
        cd->verity_root_hash_size = crypt_hash_size(params->hash_name);
        if (!cd->verity_root_hash_size)
                return -EINVAL;
 
-       cd->verity_flags = params->flags;
        cd->verity_root_hash = malloc(cd->verity_root_hash_size);
        if (!cd->verity_root_hash)
                return -ENOMEM;
 
+       cd->verity_hdr.flags = params->flags;
        cd->verity_hdr.hash_name = strdup(params->hash_name);
        cd->verity_hdr.data_device = NULL;
        cd->verity_hdr.data_block_size = params->data_block_size;
        cd->verity_hdr.hash_block_size = params->hash_block_size;
        cd->verity_hdr.hash_area_offset = params->hash_area_offset;
-       cd->verity_hdr.version = params->version;
+       cd->verity_hdr.hash_type = params->hash_type;
        cd->verity_hdr.flags = params->flags;
        cd->verity_hdr.salt_size = params->salt_size;
        cd->verity_hdr.salt = malloc(params->salt_size);
@@ -1075,24 +1079,29 @@ static int _crypt_format_verity(struct crypt_device *cd,
                r = crypt_random_get(cd, CONST_CAST(char*)cd->verity_hdr.salt,
                                     params->salt_size, CRYPT_RND_SALT);
        if (r)
-               goto out;
-
-       log_dbg("Creating verity hash on device %s.", mdata_device(cd));
-       r = VERITY_create(cd, &cd->verity_hdr, cd->device, mdata_device(cd),
-                         cd->verity_root_hash, cd->verity_root_hash_size);
-       if (r)
-               goto out;
+               return r;
 
-       r = VERITY_write_sb(cd, mdata_device(cd),
-                           cd->verity_hdr.hash_area_offset,
-                           &cd->verity_hdr);
-out:
-       if (r) {
-               free(cd->verity_root_hash);
-               free(CONST_CAST(char*)cd->verity_hdr.hash_name);
-               free(CONST_CAST(char*)cd->verity_hdr.salt);
+       if (params->flags & CRYPT_VERITY_CREATE_HASH) {
+               r = VERITY_create(cd, &cd->verity_hdr, cd->device, mdata_device(cd),
+                                 cd->verity_root_hash, cd->verity_root_hash_size);
+               if (r)
+                       return r;
        }
 
+       if (!(params->flags & CRYPT_VERITY_NO_HEADER)) {
+               if (uuid)
+                       cd->verity_uuid = strdup(uuid);
+               else {
+                       r = VERITY_UUID_generate(cd, &cd->verity_uuid);
+                       if (r)
+                               return r;
+               }
+
+               r = VERITY_write_sb(cd, mdata_device(cd),
+                                   cd->verity_hdr.hash_area_offset,
+                                   cd->verity_uuid,
+                                   &cd->verity_hdr);
+       }
        return r;
 }
 
@@ -1130,7 +1139,7 @@ int crypt_format(struct crypt_device *cd,
        else if (isLOOPAES(type))
                r = _crypt_format_loopaes(cd, cipher, uuid, volume_key_size, params);
        else if (isVERITY(type))
-               r = _crypt_format_verity(cd, params);
+               r = _crypt_format_verity(cd, uuid, params);
        else {
                /* FIXME: allow plugins here? */
                log_err(cd, _("Unknown crypt device type %s requested.\n"), type);
@@ -1320,7 +1329,6 @@ int crypt_header_restore(struct crypt_device *cd,
        if (requested_type && !isLUKS(requested_type))
                return -EINVAL;
 
-       /* Some hash functions need initialized gcrypt library */
        r = init_crypto(cd);
        if (r < 0)
                return r;
@@ -1362,6 +1370,7 @@ void crypt_free(struct crypt_device *cd)
                free(CONST_CAST(void*)cd->verity_hdr.hash_name);
                free(CONST_CAST(void*)cd->verity_hdr.salt);
                free(cd->verity_root_hash);
+               free(cd->verity_uuid);
 
                free(cd);
        }
@@ -1939,7 +1948,7 @@ int crypt_activate_by_volume_key(struct crypt_device *cd,
        struct volume_key *vk = NULL;
        int r = -EINVAL;
 
-       log_dbg("Activating volume %s by volume key.", name);
+       log_dbg("Activating volume %s by volume key.", name ?: "[none]");
 
        if (name) {
                ci = crypt_status(NULL, name);
@@ -1996,7 +2005,7 @@ int crypt_activate_by_volume_key(struct crypt_device *cd,
 
                r = VERITY_activate(cd, name, mdata_device(cd),
                                    volume_key, volume_key_size,
-                                   &cd->verity_hdr, cd->verity_flags);
+                                   &cd->verity_hdr, CRYPT_ACTIVATE_READONLY);
 
                if (r == -EPERM) {
                        free(cd->verity_root_hash);
@@ -2248,7 +2257,8 @@ static int _luks_dump(struct crypt_device *cd)
 static int _verity_dump(struct crypt_device *cd)
 {
        log_std(cd, "VERITY header information for %s\n", mdata_device(cd));
-       log_std(cd, "Version:         \t%u\n", cd->verity_hdr.version);
+       log_std(cd, "UUID:            \t%s\n", cd->verity_uuid ?: "");
+       log_std(cd, "Hash type:       \t%u\n", cd->verity_hdr.hash_type);
        log_std(cd, "Data blocks:     \t%" PRIu64 "\n", cd->verity_hdr.data_size);
        log_std(cd, "Data block size: \t%u\n", cd->verity_hdr.data_block_size);
        log_std(cd, "Hash block size: \t%u\n", cd->verity_hdr.hash_block_size);
@@ -2317,6 +2327,9 @@ const char *crypt_get_uuid(struct crypt_device *cd)
        if (isLOOPAES(cd->type))
                return cd->loopaes_uuid;
 
+       if (isVERITY(cd->type))
+               return cd->verity_uuid;
+
        return NULL;
 }
 
@@ -2393,6 +2406,26 @@ const char *crypt_get_type(struct crypt_device *cd)
        return cd->type;
 }
 
+int crypt_get_verity_info(struct crypt_device *cd,
+       struct crypt_params_verity *vp)
+{
+       if (!isVERITY(cd->type) || !vp)
+               return -EINVAL;
+
+       vp->data_device = cd->device;
+       vp->hash_device = mdata_device(cd);
+       vp->hash_name = cd->verity_hdr.hash_name;
+       vp->salt = cd->verity_hdr.salt;
+       vp->salt_size = cd->verity_hdr.salt_size;
+       vp->data_block_size = cd->verity_hdr.data_block_size;
+       vp->hash_block_size = cd->verity_hdr.hash_block_size;
+       vp->data_size = cd->verity_hdr.data_size;
+       vp->hash_area_offset = cd->verity_hdr.hash_area_offset;
+       vp->hash_type = cd->verity_hdr.hash_type;
+       vp->flags = cd->verity_hdr.flags & CRYPT_VERITY_NO_HEADER;
+       return 0;
+}
+
 int crypt_get_active_device(struct crypt_device *cd __attribute__((unused)),
                            const char *name,
                            struct crypt_active_device *cad)
@@ -2404,7 +2437,7 @@ int crypt_get_active_device(struct crypt_device *cd __attribute__((unused)),
        if (r < 0)
                return r;
 
-       if (dmd.target != DM_CRYPT)
+       if (dmd.target != DM_CRYPT && dmd.target != DM_VERITY)
                return -ENOTSUP;
 
        cad->offset     = dmd.u.crypt.offset;