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 |
| 17 | * License along with this library; if not, write to the Free Software |
| 18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| 19 | */ |
| 20 | |
| 21 | #include <endian.h> |
| 22 | #include <stdint.h> |
| 23 | #include <stdlib.h> |
| 24 | #include <string.h> |
| 25 | #include <stdio.h> |
| 26 | |
| 27 | #include "libkmod-private.h" |
| 28 | |
| 29 | /* These types and tables were copied from the 3.7 kernel sources. |
| 30 | * As this is just description of the signature format, it should not be |
| 31 | * considered derived work (so libkmod can use the LGPL license). |
| 32 | */ |
| 33 | enum pkey_algo { |
| 34 | PKEY_ALGO_DSA, |
| 35 | PKEY_ALGO_RSA, |
| 36 | PKEY_ALGO__LAST |
| 37 | }; |
| 38 | |
| 39 | static const char *const pkey_algo[PKEY_ALGO__LAST] = { |
| 40 | [PKEY_ALGO_DSA] = "DSA", |
| 41 | [PKEY_ALGO_RSA] = "RSA", |
| 42 | }; |
| 43 | |
| 44 | enum pkey_hash_algo { |
| 45 | PKEY_HASH_MD4, |
| 46 | PKEY_HASH_MD5, |
| 47 | PKEY_HASH_SHA1, |
| 48 | PKEY_HASH_RIPE_MD_160, |
| 49 | PKEY_HASH_SHA256, |
| 50 | PKEY_HASH_SHA384, |
| 51 | PKEY_HASH_SHA512, |
| 52 | PKEY_HASH_SHA224, |
| 53 | PKEY_HASH__LAST |
| 54 | }; |
| 55 | |
| 56 | const char *const pkey_hash_algo[PKEY_HASH__LAST] = { |
| 57 | [PKEY_HASH_MD4] = "md4", |
| 58 | [PKEY_HASH_MD5] = "md5", |
| 59 | [PKEY_HASH_SHA1] = "sha1", |
| 60 | [PKEY_HASH_RIPE_MD_160] = "rmd160", |
| 61 | [PKEY_HASH_SHA256] = "sha256", |
| 62 | [PKEY_HASH_SHA384] = "sha384", |
| 63 | [PKEY_HASH_SHA512] = "sha512", |
| 64 | [PKEY_HASH_SHA224] = "sha224", |
| 65 | }; |
| 66 | |
| 67 | enum pkey_id_type { |
| 68 | PKEY_ID_PGP, /* OpenPGP generated key ID */ |
| 69 | PKEY_ID_X509, /* X.509 arbitrary subjectKeyIdentifier */ |
| 70 | PKEY_ID_TYPE__LAST |
| 71 | }; |
| 72 | |
| 73 | const char *const pkey_id_type[PKEY_ID_TYPE__LAST] = { |
| 74 | [PKEY_ID_PGP] = "PGP", |
| 75 | [PKEY_ID_X509] = "X509", |
| 76 | }; |
| 77 | |
| 78 | /* |
| 79 | * Module signature information block. |
| 80 | * |
| 81 | * The constituents of the signature section are, in order: |
| 82 | * |
| 83 | * - Signer's name |
| 84 | * - Key identifier |
| 85 | * - Signature data |
| 86 | * - Information block |
| 87 | */ |
| 88 | struct module_signature { |
| 89 | uint8_t algo; /* Public-key crypto algorithm [enum pkey_algo] */ |
| 90 | uint8_t hash; /* Digest algorithm [enum pkey_hash_algo] */ |
| 91 | uint8_t id_type; /* Key identifier type [enum pkey_id_type] */ |
| 92 | uint8_t signer_len; /* Length of signer's name */ |
| 93 | uint8_t key_id_len; /* Length of key identifier */ |
| 94 | uint8_t __pad[3]; |
| 95 | uint32_t sig_len; /* Length of signature data (big endian) */ |
| 96 | }; |
| 97 | |
| 98 | #define SIG_MAGIC "~Module signature appended~\n" |
| 99 | |
| 100 | bool kmod_module_signature_info(const struct kmod_file *file, struct kmod_signature_info *sig_info) |
| 101 | { |
| 102 | const char *mem; |
| 103 | off_t size; |
| 104 | const struct module_signature *modsig; |
| 105 | size_t sig_len; |
| 106 | |
| 107 | |
| 108 | size = kmod_file_get_size(file); |
| 109 | mem = kmod_file_get_contents(file); |
| 110 | if (size < (off_t)strlen(SIG_MAGIC)) |
| 111 | return false; |
| 112 | size -= strlen(SIG_MAGIC); |
| 113 | if (memcmp(SIG_MAGIC, mem + size, strlen(SIG_MAGIC)) != 0) |
| 114 | return false; |
| 115 | |
| 116 | if (size < (off_t)sizeof(struct module_signature)) |
| 117 | return false; |
| 118 | size -= sizeof(struct module_signature); |
| 119 | modsig = (struct module_signature *)(mem + size); |
| 120 | if (modsig->algo >= PKEY_ALGO__LAST || |
| 121 | modsig->hash >= PKEY_HASH__LAST || |
| 122 | modsig->id_type >= PKEY_ID_TYPE__LAST) |
| 123 | return false; |
| 124 | sig_len = be32toh(modsig->sig_len); |
| 125 | if (size < (off_t)(modsig->signer_len + modsig->key_id_len + sig_len)) |
| 126 | return false; |
| 127 | |
| 128 | size -= modsig->key_id_len + sig_len; |
| 129 | sig_info->key_id = mem + size; |
| 130 | sig_info->key_id_len = modsig->key_id_len; |
| 131 | |
| 132 | size -= modsig->signer_len; |
| 133 | sig_info->signer = mem + size; |
| 134 | sig_info->signer_len = modsig->signer_len; |
| 135 | |
| 136 | sig_info->algo = pkey_algo[modsig->algo]; |
| 137 | sig_info->hash_algo = pkey_hash_algo[modsig->hash]; |
| 138 | sig_info->id_type = pkey_id_type[modsig->id_type]; |
| 139 | |
| 140 | return true; |
| 141 | } |