fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / crypto / signature / ksign.c
1 /* ksign.c: signature checker
2  *
3  * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
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.
10  */
11
12 #include <linux/kernel.h>
13 #include <asm/errno.h>
14 #include "local.h"
15
16 #if 0
17 #define _debug(FMT, ...) printk(KERN_DEBUG FMT, ##__VA_ARGS__)
18 #else
19 #define _debug(FMT, ...) do { ; } while (0)
20 #endif
21
22 /*
23  * check the signature which is contained in SIG.
24  */
25 static int ksign_signature_check(const struct ksign_signature *sig,
26                                  struct crypto_hash *sha1_tfm)
27 {
28         struct ksign_public_key *pk;
29         struct hash_desc sha1_d;
30         uint8_t sha1[SHA1_DIGEST_SIZE];
31         MPI result = NULL;
32         int rc = 0;
33
34         pk = ksign_get_public_key(sig->keyid);
35         if (!pk) {
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);
39                 return -ENOKEY;
40         }
41
42         if (pk->timestamp > sig->timestamp)
43                 printk("ksign:"
44                        " public key is %lu seconds newer than the signature\n",
45                        pk->timestamp - sig->timestamp);
46
47         sha1_d.tfm = sha1_tfm;
48         sha1_d.flags = 0;
49
50         /* complete the digest */
51         if (sig->version >= 4)
52                 SHA1_putc(&sha1_d, sig->version);
53         SHA1_putc(&sha1_d, sig->sig_class);
54
55         if (sig->version < 4) {
56                 u32 a = sig->timestamp;
57                 SHA1_putc(&sha1_d, (a >> 24) & 0xff);
58                 SHA1_putc(&sha1_d, (a >> 16) & 0xff);
59                 SHA1_putc(&sha1_d, (a >>  8) & 0xff);
60                 SHA1_putc(&sha1_d, (a >>  0) & 0xff);
61         }
62         else {
63                 uint8_t buf[6];
64                 size_t n;
65                 SHA1_putc(&sha1_d, PUBKEY_ALGO_DSA);
66                 SHA1_putc(&sha1_d, DIGEST_ALGO_SHA1);
67                 if (sig->hashed_data) {
68                         n = (sig->hashed_data[0] << 8) | sig->hashed_data[1];
69                         SHA1_write(&sha1_d, sig->hashed_data, n + 2);
70                         n += 6;
71                 }
72                 else {
73                         n = 6;
74                 }
75
76                 /* add some magic */
77                 buf[0] = sig->version;
78                 buf[1] = 0xff;
79                 buf[2] = n >> 24;
80                 buf[3] = n >> 16;
81                 buf[4] = n >>  8;
82                 buf[5] = n;
83                 SHA1_write(&sha1_d, buf, 6);
84         }
85
86         crypto_hash_final(&sha1_d, sha1);
87         crypto_free_hash(sha1_tfm);
88
89         rc = -ENOMEM;
90         result = mpi_alloc((SHA1_DIGEST_SIZE + BYTES_PER_MPI_LIMB - 1) /
91                            BYTES_PER_MPI_LIMB);
92         if (!result)
93                 goto cleanup;
94
95         rc = mpi_set_buffer(result, sha1, SHA1_DIGEST_SIZE, 0);
96         if (rc < 0)
97                 goto cleanup;
98
99         rc = DSA_verify(result, sig->data, pk->pkey);
100
101  cleanup:
102         mpi_free(result);
103         ksign_put_public_key(pk);
104
105         return rc;
106 }
107
108 /*
109  * examine the signatures that are parsed out of the signature data - we keep
110  * the first one that's appropriate and ignore the rest
111  * - return 0 if signature of interest (sig not freed by caller)
112  * - return 1 if no interest (caller frees)
113  */
114 static int ksign_grab_signature(struct ksign_signature *sig, void *fnxdata)
115 {
116         struct ksign_signature **_sig = fnxdata;
117
118         if (sig->sig_class != 0x00) {
119                 _debug("ksign: standalone signature of class 0x%02x\n",
120                        sig->sig_class);
121                 return 1;
122         }
123
124         if (*_sig)
125                 return 1;
126
127         *_sig = sig;
128         return 0;
129 }
130
131 /*
132  * verify the signature of some data with one of the kernel's known public keys
133  * - the SHA1 context should be currently open with the signed data digested
134  *   into it so that more data can be appended
135  * - the SHA1 context is finalised and freed before returning
136  */
137 int ksign_verify_signature(const char *sigdata, unsigned sig_size,
138                            struct crypto_hash *sha1)
139 {
140         struct ksign_signature *sig = NULL;
141         int retval;
142
143         /* parse the signature data to get the actual signature */
144         retval = ksign_parse_packets(sigdata, sig_size,
145                                      &ksign_grab_signature, NULL, NULL,
146                                      &sig);
147         if (retval < 0)
148                 goto cleanup;
149
150         if (!sig) {
151                 printk(KERN_NOTICE
152                        "Couldn't find valid DSA signature in module\n");
153                 return -ENOENT;
154         }
155
156         _debug("signature keyid: %08x%08x ver=%u\n",
157                sig->keyid[0], sig->keyid[1], sig->version);
158
159         /* check the data SHA1 transformation against the public key */
160         retval = ksign_signature_check(sig, sha1);
161         switch (retval) {
162         case 0:
163                 _debug("ksign: Signature check succeeded\n");
164                 break;
165         case -ENOMEM:
166                 _debug("ksign: Signature check ENOMEM\n");
167                 break;
168         default:
169                 _debug("ksign: Signature check failed\n");
170                 if (retval != -ENOKEY)
171                         retval = -EKEYREJECTED;
172                 break;
173         }
174
175  cleanup:
176         if (sig)
177                 ksign_free_signature(sig);
178
179         return retval;
180 }