Michal Marek | 8fe1681 | 2013-01-16 09:52:01 +0100 | [diff] [blame] | 1 | /* |
| 2 | * libkmod - module signature display |
| 3 | * |
| 4 | * Copyright (C) 2013 Michal Marek, SUSE |
| 5 | * |
| 6 | * This library is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU Lesser General Public |
| 8 | * License as published by the Free Software Foundation; either |
| 9 | * version 2.1 of the License, or (at your option) any later version. |
| 10 | * |
| 11 | * This library is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 14 | * Lesser General Public License for more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU Lesser General Public |
Lucas De Marchi | dea2dfe | 2014-12-25 23:32:03 -0200 | [diff] [blame] | 17 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
Michal Marek | 8fe1681 | 2013-01-16 09:52:01 +0100 | [diff] [blame] | 18 | */ |
| 19 | |
| 20 | #include <endian.h> |
Lucas De Marchi | b18979b | 2014-10-03 02:03:55 -0300 | [diff] [blame] | 21 | #include <inttypes.h> |
Lucas De Marchi | c2e4286 | 2014-10-03 01:41:42 -0300 | [diff] [blame] | 22 | #include <stdio.h> |
Michal Marek | 8fe1681 | 2013-01-16 09:52:01 +0100 | [diff] [blame] | 23 | #include <stdlib.h> |
| 24 | #include <string.h> |
Michal Marek | 8fe1681 | 2013-01-16 09:52:01 +0100 | [diff] [blame] | 25 | |
Lucas De Marchi | 8b7189b | 2014-10-02 22:08:47 -0300 | [diff] [blame] | 26 | #include <shared/missing.h> |
Lucas De Marchi | 96573a0 | 2014-10-03 00:01:35 -0300 | [diff] [blame] | 27 | #include <shared/util.h> |
Lucas De Marchi | 8b7189b | 2014-10-02 22:08:47 -0300 | [diff] [blame] | 28 | |
Lucas De Marchi | 83b855a | 2013-07-04 16:13:11 -0300 | [diff] [blame] | 29 | #include "libkmod-internal.h" |
Michal Marek | 8fe1681 | 2013-01-16 09:52:01 +0100 | [diff] [blame] | 30 | |
| 31 | /* These types and tables were copied from the 3.7 kernel sources. |
| 32 | * As this is just description of the signature format, it should not be |
| 33 | * considered derived work (so libkmod can use the LGPL license). |
| 34 | */ |
| 35 | enum pkey_algo { |
| 36 | PKEY_ALGO_DSA, |
| 37 | PKEY_ALGO_RSA, |
| 38 | PKEY_ALGO__LAST |
| 39 | }; |
| 40 | |
| 41 | static const char *const pkey_algo[PKEY_ALGO__LAST] = { |
| 42 | [PKEY_ALGO_DSA] = "DSA", |
| 43 | [PKEY_ALGO_RSA] = "RSA", |
| 44 | }; |
| 45 | |
| 46 | enum pkey_hash_algo { |
| 47 | PKEY_HASH_MD4, |
| 48 | PKEY_HASH_MD5, |
| 49 | PKEY_HASH_SHA1, |
| 50 | PKEY_HASH_RIPE_MD_160, |
| 51 | PKEY_HASH_SHA256, |
| 52 | PKEY_HASH_SHA384, |
| 53 | PKEY_HASH_SHA512, |
| 54 | PKEY_HASH_SHA224, |
| 55 | PKEY_HASH__LAST |
| 56 | }; |
| 57 | |
| 58 | const char *const pkey_hash_algo[PKEY_HASH__LAST] = { |
| 59 | [PKEY_HASH_MD4] = "md4", |
| 60 | [PKEY_HASH_MD5] = "md5", |
| 61 | [PKEY_HASH_SHA1] = "sha1", |
| 62 | [PKEY_HASH_RIPE_MD_160] = "rmd160", |
| 63 | [PKEY_HASH_SHA256] = "sha256", |
| 64 | [PKEY_HASH_SHA384] = "sha384", |
| 65 | [PKEY_HASH_SHA512] = "sha512", |
| 66 | [PKEY_HASH_SHA224] = "sha224", |
| 67 | }; |
| 68 | |
| 69 | enum pkey_id_type { |
| 70 | PKEY_ID_PGP, /* OpenPGP generated key ID */ |
| 71 | PKEY_ID_X509, /* X.509 arbitrary subjectKeyIdentifier */ |
| 72 | PKEY_ID_TYPE__LAST |
| 73 | }; |
| 74 | |
| 75 | const char *const pkey_id_type[PKEY_ID_TYPE__LAST] = { |
| 76 | [PKEY_ID_PGP] = "PGP", |
| 77 | [PKEY_ID_X509] = "X509", |
| 78 | }; |
| 79 | |
| 80 | /* |
| 81 | * Module signature information block. |
Michal Marek | 8fe1681 | 2013-01-16 09:52:01 +0100 | [diff] [blame] | 82 | */ |
| 83 | struct module_signature { |
| 84 | uint8_t algo; /* Public-key crypto algorithm [enum pkey_algo] */ |
| 85 | uint8_t hash; /* Digest algorithm [enum pkey_hash_algo] */ |
| 86 | uint8_t id_type; /* Key identifier type [enum pkey_id_type] */ |
| 87 | uint8_t signer_len; /* Length of signer's name */ |
| 88 | uint8_t key_id_len; /* Length of key identifier */ |
| 89 | uint8_t __pad[3]; |
| 90 | uint32_t sig_len; /* Length of signature data (big endian) */ |
| 91 | }; |
| 92 | |
| 93 | #define SIG_MAGIC "~Module signature appended~\n" |
| 94 | |
Lucas De Marchi | 885e90b | 2015-02-18 16:47:14 -0200 | [diff] [blame] | 95 | /* |
| 96 | * A signed module has the following layout: |
| 97 | * |
| 98 | * [ module ] |
| 99 | * [ signer's name ] |
| 100 | * [ key identifier ] |
| 101 | * [ signature data ] |
| 102 | * [ struct module_signature ] |
| 103 | * [ SIG_MAGIC ] |
| 104 | */ |
| 105 | |
Michal Marek | 8fe1681 | 2013-01-16 09:52:01 +0100 | [diff] [blame] | 106 | bool kmod_module_signature_info(const struct kmod_file *file, struct kmod_signature_info *sig_info) |
| 107 | { |
| 108 | const char *mem; |
| 109 | off_t size; |
| 110 | const struct module_signature *modsig; |
| 111 | size_t sig_len; |
| 112 | |
| 113 | |
| 114 | size = kmod_file_get_size(file); |
| 115 | mem = kmod_file_get_contents(file); |
| 116 | if (size < (off_t)strlen(SIG_MAGIC)) |
| 117 | return false; |
| 118 | size -= strlen(SIG_MAGIC); |
| 119 | if (memcmp(SIG_MAGIC, mem + size, strlen(SIG_MAGIC)) != 0) |
| 120 | return false; |
| 121 | |
| 122 | if (size < (off_t)sizeof(struct module_signature)) |
| 123 | return false; |
| 124 | size -= sizeof(struct module_signature); |
| 125 | modsig = (struct module_signature *)(mem + size); |
| 126 | if (modsig->algo >= PKEY_ALGO__LAST || |
| 127 | modsig->hash >= PKEY_HASH__LAST || |
| 128 | modsig->id_type >= PKEY_ID_TYPE__LAST) |
| 129 | return false; |
Lucas De Marchi | f87dc57 | 2014-03-24 14:33:50 -0300 | [diff] [blame] | 130 | sig_len = be32toh(get_unaligned(&modsig->sig_len)); |
Lucas De Marchi | dcbe184 | 2015-02-18 16:15:45 -0200 | [diff] [blame] | 131 | if (sig_len == 0 || |
| 132 | size < (int64_t)(modsig->signer_len + modsig->key_id_len + sig_len)) |
Michal Marek | 8fe1681 | 2013-01-16 09:52:01 +0100 | [diff] [blame] | 133 | return false; |
| 134 | |
| 135 | size -= modsig->key_id_len + sig_len; |
| 136 | sig_info->key_id = mem + size; |
| 137 | sig_info->key_id_len = modsig->key_id_len; |
| 138 | |
| 139 | size -= modsig->signer_len; |
| 140 | sig_info->signer = mem + size; |
| 141 | sig_info->signer_len = modsig->signer_len; |
| 142 | |
| 143 | sig_info->algo = pkey_algo[modsig->algo]; |
| 144 | sig_info->hash_algo = pkey_hash_algo[modsig->hash]; |
| 145 | sig_info->id_type = pkey_id_type[modsig->id_type]; |
| 146 | |
| 147 | return true; |
| 148 | } |