Blame libkmod/libkmod-signature.c

Packit a3a425
/*
Packit a3a425
 * libkmod - module signature display
Packit a3a425
 *
Packit a3a425
 * Copyright (C) 2013 Michal Marek, SUSE
Packit a3a425
 *
Packit a3a425
 * This library is free software; you can redistribute it and/or
Packit a3a425
 * modify it under the terms of the GNU Lesser General Public
Packit a3a425
 * License as published by the Free Software Foundation; either
Packit a3a425
 * version 2.1 of the License, or (at your option) any later version.
Packit a3a425
 *
Packit a3a425
 * This library is distributed in the hope that it will be useful,
Packit a3a425
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit a3a425
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit a3a425
 * Lesser General Public License for more details.
Packit a3a425
 *
Packit a3a425
 * You should have received a copy of the GNU Lesser General Public
Packit a3a425
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit a3a425
 */
Packit a3a425
Packit a3a425
#include <endian.h>
Packit a3a425
#include <inttypes.h>
Packit a3a425
#include <stdio.h>
Packit a3a425
#include <stdlib.h>
Packit a3a425
#include <string.h>
Packit a3a425
Packit a3a425
#include <shared/missing.h>
Packit a3a425
#include <shared/util.h>
Packit a3a425
Packit a3a425
#include "libkmod-internal.h"
Packit a3a425
Packit a3a425
/* These types and tables were copied from the 3.7 kernel sources.
Packit a3a425
 * As this is just description of the signature format, it should not be
Packit a3a425
 * considered derived work (so libkmod can use the LGPL license).
Packit a3a425
 */
Packit a3a425
enum pkey_algo {
Packit a3a425
	PKEY_ALGO_DSA,
Packit a3a425
	PKEY_ALGO_RSA,
Packit a3a425
	PKEY_ALGO__LAST
Packit a3a425
};
Packit a3a425
Packit a3a425
static const char *const pkey_algo[PKEY_ALGO__LAST] = {
Packit a3a425
	[PKEY_ALGO_DSA]		= "DSA",
Packit a3a425
	[PKEY_ALGO_RSA]		= "RSA",
Packit a3a425
};
Packit a3a425
Packit a3a425
enum pkey_hash_algo {
Packit a3a425
	PKEY_HASH_MD4,
Packit a3a425
	PKEY_HASH_MD5,
Packit a3a425
	PKEY_HASH_SHA1,
Packit a3a425
	PKEY_HASH_RIPE_MD_160,
Packit a3a425
	PKEY_HASH_SHA256,
Packit a3a425
	PKEY_HASH_SHA384,
Packit a3a425
	PKEY_HASH_SHA512,
Packit a3a425
	PKEY_HASH_SHA224,
Packit a3a425
	PKEY_HASH__LAST
Packit a3a425
};
Packit a3a425
Packit a3a425
const char *const pkey_hash_algo[PKEY_HASH__LAST] = {
Packit a3a425
	[PKEY_HASH_MD4]		= "md4",
Packit a3a425
	[PKEY_HASH_MD5]		= "md5",
Packit a3a425
	[PKEY_HASH_SHA1]	= "sha1",
Packit a3a425
	[PKEY_HASH_RIPE_MD_160]	= "rmd160",
Packit a3a425
	[PKEY_HASH_SHA256]	= "sha256",
Packit a3a425
	[PKEY_HASH_SHA384]	= "sha384",
Packit a3a425
	[PKEY_HASH_SHA512]	= "sha512",
Packit a3a425
	[PKEY_HASH_SHA224]	= "sha224",
Packit a3a425
};
Packit a3a425
Packit a3a425
enum pkey_id_type {
Packit a3a425
	PKEY_ID_PGP,		/* OpenPGP generated key ID */
Packit a3a425
	PKEY_ID_X509,		/* X.509 arbitrary subjectKeyIdentifier */
Packit a3a425
	PKEY_ID_PKCS7,		/* Signature in PKCS#7 message */
Packit a3a425
	PKEY_ID_TYPE__LAST
Packit a3a425
};
Packit a3a425
Packit a3a425
const char *const pkey_id_type[PKEY_ID_TYPE__LAST] = {
Packit a3a425
	[PKEY_ID_PGP]		= "PGP",
Packit a3a425
	[PKEY_ID_X509]		= "X509",
Packit a3a425
	[PKEY_ID_PKCS7]		= "PKCS#7",
Packit a3a425
};
Packit a3a425
Packit a3a425
/*
Packit a3a425
 * Module signature information block.
Packit a3a425
 */
Packit a3a425
struct module_signature {
Packit a3a425
	uint8_t algo;        /* Public-key crypto algorithm [enum pkey_algo] */
Packit a3a425
	uint8_t hash;        /* Digest algorithm [enum pkey_hash_algo] */
Packit a3a425
	uint8_t id_type;     /* Key identifier type [enum pkey_id_type] */
Packit a3a425
	uint8_t signer_len;  /* Length of signer's name */
Packit a3a425
	uint8_t key_id_len;  /* Length of key identifier */
Packit a3a425
	uint8_t __pad[3];
Packit a3a425
	uint32_t sig_len;    /* Length of signature data (big endian) */
Packit a3a425
};
Packit a3a425
Packit a3a425
#define SIG_MAGIC "~Module signature appended~\n"
Packit a3a425
Packit a3a425
/*
Packit a3a425
 * A signed module has the following layout:
Packit a3a425
 *
Packit a3a425
 * [ module                  ]
Packit a3a425
 * [ signer's name           ]
Packit a3a425
 * [ key identifier          ]
Packit a3a425
 * [ signature data          ]
Packit a3a425
 * [ struct module_signature ]
Packit a3a425
 * [ SIG_MAGIC               ]
Packit a3a425
 */
Packit a3a425
Packit a3a425
bool kmod_module_signature_info(const struct kmod_file *file, struct kmod_signature_info *sig_info)
Packit a3a425
{
Packit a3a425
	const char *mem;
Packit a3a425
	off_t size;
Packit a3a425
	const struct module_signature *modsig;
Packit a3a425
	size_t sig_len;
Packit a3a425
Packit Service 9de8ea
Packit a3a425
	size = kmod_file_get_size(file);
Packit a3a425
	mem = kmod_file_get_contents(file);
Packit a3a425
	if (size < (off_t)strlen(SIG_MAGIC))
Packit a3a425
		return false;
Packit a3a425
	size -= strlen(SIG_MAGIC);
Packit a3a425
	if (memcmp(SIG_MAGIC, mem + size, strlen(SIG_MAGIC)) != 0)
Packit a3a425
		return false;
Packit a3a425
Packit a3a425
	if (size < (off_t)sizeof(struct module_signature))
Packit a3a425
		return false;
Packit a3a425
	size -= sizeof(struct module_signature);
Packit a3a425
	modsig = (struct module_signature *)(mem + size);
Packit a3a425
	if (modsig->algo >= PKEY_ALGO__LAST ||
Packit a3a425
			modsig->hash >= PKEY_HASH__LAST ||
Packit a3a425
			modsig->id_type >= PKEY_ID_TYPE__LAST)
Packit a3a425
		return false;
Packit a3a425
	sig_len = be32toh(get_unaligned(&modsig->sig_len));
Packit a3a425
	if (sig_len == 0 ||
Packit a3a425
	    size < (int64_t)(modsig->signer_len + modsig->key_id_len + sig_len))
Packit a3a425
		return false;
Packit a3a425
Packit Service 9de8ea
	size -= sig_len;
Packit Service 9de8ea
	sig_info->sig = mem + size;
Packit Service 9de8ea
	sig_info->sig_len = sig_len;
Packit Service 879dec
Packit Service 9de8ea
	size -= modsig->key_id_len;
Packit Service 9de8ea
	sig_info->key_id = mem + size;
Packit Service 9de8ea
	sig_info->key_id_len = modsig->key_id_len;
Packit Service 9de8ea
Packit Service 9de8ea
	size -= modsig->signer_len;
Packit Service 9de8ea
	sig_info->signer = mem + size;
Packit Service 9de8ea
	sig_info->signer_len = modsig->signer_len;
Packit Service 9de8ea
Packit Service 9de8ea
	sig_info->algo = pkey_algo[modsig->algo];
Packit Service 9de8ea
	sig_info->hash_algo = pkey_hash_algo[modsig->hash];
Packit Service 9de8ea
	sig_info->id_type = pkey_id_type[modsig->id_type];
Packit Service 9de8ea
Packit Service 9de8ea
	return true;
Packit Service 879dec
}