1 /* ksign.c: signature checker
3 * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
12 #include <linux/kernel.h>
13 #include <asm/errno.h>
17 #define _debug(FMT, ...) printk(KERN_DEBUG FMT, ##__VA_ARGS__)
19 #define _debug(FMT, ...) do { ; } while (0)
22 /*****************************************************************************/
24 * check the signature which is contained in SIG.
26 static int ksign_signature_check(const struct ksign_signature *sig,
27 struct crypto_tfm *sha1_tfm)
29 struct ksign_public_key *pk;
30 uint8_t sha1[SHA1_DIGEST_SIZE];
34 pk = ksign_get_public_key(sig->keyid);
36 printk("ksign: module signed with unknown public key\n");
37 printk("- signature keyid: %08x%08x ver=%u\n",
38 sig->keyid[0], sig->keyid[1], sig->version);
42 if (pk->timestamp > sig->timestamp)
44 " public key is %lu seconds newer than the signature\n",
45 pk->timestamp - sig->timestamp);
47 /* complete the digest */
48 if (sig->version >= 4)
49 SHA1_putc(sha1_tfm, sig->version);
50 SHA1_putc(sha1_tfm, sig->sig_class);
52 if (sig->version < 4) {
53 u32 a = sig->timestamp;
54 SHA1_putc(sha1_tfm, (a >> 24) & 0xff);
55 SHA1_putc(sha1_tfm, (a >> 16) & 0xff);
56 SHA1_putc(sha1_tfm, (a >> 8) & 0xff);
57 SHA1_putc(sha1_tfm, (a >> 0) & 0xff);
62 SHA1_putc(sha1_tfm, PUBKEY_ALGO_DSA);
63 SHA1_putc(sha1_tfm, DIGEST_ALGO_SHA1);
64 if (sig->hashed_data) {
65 n = (sig->hashed_data[0] << 8) | sig->hashed_data[1];
66 SHA1_write(sha1_tfm, sig->hashed_data, n + 2);
74 buf[0] = sig->version;
80 SHA1_write(sha1_tfm, buf, 6);
83 crypto_digest_final(sha1_tfm, sha1);
84 crypto_free_tfm(sha1_tfm);
92 result = mpi_alloc((SHA1_DIGEST_SIZE + BYTES_PER_MPI_LIMB - 1) / BYTES_PER_MPI_LIMB);
96 rc = mpi_set_buffer(result, sha1, SHA1_DIGEST_SIZE, 0);
100 rc = DSA_verify(result, sig->data, pk->pkey);
104 ksign_put_public_key(pk);
107 } /* end ksign_signature_check() */
109 /*****************************************************************************/
111 * examine the signatures that are parsed out of the signature data - we keep
112 * the first one that's appropriate and ignore the rest
113 * - return 0 if signature of interest (sig not freed by caller)
114 * - return 1 if no interest (caller frees)
116 static int ksign_grab_signature(struct ksign_signature *sig, void *fnxdata)
118 struct ksign_signature **_sig = fnxdata;
120 if (sig->sig_class != 0x00) {
121 _debug("ksign: standalone signature of class 0x%02x\n",
131 } /* end ksign_grab_signature() */
133 /*****************************************************************************/
135 * verify the signature of some data with one of the kernel's known public keys
136 * - the SHA1 context should be currently open with the signed data digested
137 * into it so that more data can be appended
138 * - the SHA1 context is finalised and freed before returning
140 int ksign_verify_signature(const char *sigdata, unsigned sig_size,
141 struct crypto_tfm *sha1)
143 struct ksign_signature *sig = NULL;
146 /* parse the signature data to get the actual signature */
147 retval = ksign_parse_packets(sigdata, sig_size,
148 &ksign_grab_signature, NULL, NULL,
154 printk("Couldn't find valid DSA signature in module\n");
158 _debug("signature keyid: %08x%08x ver=%u\n",
159 sig->keyid[0], sig->keyid[1], sig->version);
161 /* check the data SHA1 transformation against the public key */
162 retval = ksign_signature_check(sig, sha1);
164 _debug("ksign: Signature check succeeded\n");
166 else if (retval != -ENOMEM) {
167 _debug("ksign: Signature check failed\n");
171 _debug("ksign: Signature check ENOMEM\n");
176 ksign_free_signature(sig);
179 } /* end ksign_verify_signature() */