~ubuntu-branches/ubuntu/oneiric/postgresql-9.1/oneiric-security

« back to all changes in this revision

Viewing changes to contrib/pgcrypto/px.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2011-05-11 10:41:53 UTC
  • Revision ID: james.westby@ubuntu.com-20110511104153-psbh2o58553fv1m0
Tags: upstream-9.1~beta1
ImportĀ upstreamĀ versionĀ 9.1~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * px.c
 
3
 *              Various cryptographic stuff for PostgreSQL.
 
4
 *
 
5
 * Copyright (c) 2001 Marko Kreen
 
6
 * All rights reserved.
 
7
 *
 
8
 * Redistribution and use in source and binary forms, with or without
 
9
 * modification, are permitted provided that the following conditions
 
10
 * are met:
 
11
 * 1. Redistributions of source code must retain the above copyright
 
12
 *        notice, this list of conditions and the following disclaimer.
 
13
 * 2. Redistributions in binary form must reproduce the above copyright
 
14
 *        notice, this list of conditions and the following disclaimer in the
 
15
 *        documentation and/or other materials provided with the distribution.
 
16
 *
 
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
20
 * ARE DISCLAIMED.      IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
27
 * SUCH DAMAGE.
 
28
 *
 
29
 * contrib/pgcrypto/px.c
 
30
 */
 
31
 
 
32
#include "postgres.h"
 
33
 
 
34
#include "px.h"
 
35
 
 
36
struct error_desc
 
37
{
 
38
        int                     err;
 
39
        const char *desc;
 
40
};
 
41
 
 
42
static const struct error_desc px_err_list[] = {
 
43
        {PXE_OK, "Everything ok"},
 
44
        {PXE_ERR_GENERIC, "Some PX error (not specified)"},
 
45
        {PXE_NO_HASH, "No such hash algorithm"},
 
46
        {PXE_NO_CIPHER, "No such cipher algorithm"},
 
47
        {PXE_NOTBLOCKSIZE, "Data not a multiple of block size"},
 
48
        {PXE_BAD_OPTION, "Unknown option"},
 
49
        {PXE_BAD_FORMAT, "Badly formatted type"},
 
50
        {PXE_KEY_TOO_BIG, "Key was too big"},
 
51
        {PXE_CIPHER_INIT, "Cipher cannot be initalized ?"},
 
52
        {PXE_HASH_UNUSABLE_FOR_HMAC, "This hash algorithm is unusable for HMAC"},
 
53
        {PXE_DEV_READ_ERROR, "Error reading from random device"},
 
54
        {PXE_OSSL_RAND_ERROR, "OpenSSL PRNG error"},
 
55
        {PXE_BUG, "pgcrypto bug"},
 
56
        {PXE_ARGUMENT_ERROR, "Illegal argument to function"},
 
57
        {PXE_UNKNOWN_SALT_ALGO, "Unknown salt algorithm"},
 
58
        {PXE_BAD_SALT_ROUNDS, "Incorrect number of rounds"},
 
59
        {PXE_MCRYPT_INTERNAL, "mcrypt internal error"},
 
60
        {PXE_NO_RANDOM, "No strong random source"},
 
61
        {PXE_DECRYPT_FAILED, "Decryption failed"},
 
62
        {PXE_PGP_CORRUPT_DATA, "Wrong key or corrupt data"},
 
63
        {PXE_PGP_CORRUPT_ARMOR, "Corrupt ascii-armor"},
 
64
        {PXE_PGP_UNSUPPORTED_COMPR, "Unsupported compression algorithm"},
 
65
        {PXE_PGP_UNSUPPORTED_CIPHER, "Unsupported cipher algorithm"},
 
66
        {PXE_PGP_UNSUPPORTED_HASH, "Unsupported digest algorithm"},
 
67
        {PXE_PGP_COMPRESSION_ERROR, "Compression error"},
 
68
        {PXE_PGP_NOT_TEXT, "Not text data"},
 
69
        {PXE_PGP_UNEXPECTED_PKT, "Unexpected packet in key data"},
 
70
        {PXE_PGP_NO_BIGNUM,
 
71
                "public-key functions disabled - "
 
72
        "pgcrypto needs OpenSSL for bignums"},
 
73
        {PXE_PGP_MATH_FAILED, "Math operation failed"},
 
74
        {PXE_PGP_SHORT_ELGAMAL_KEY, "Elgamal keys must be at least 1024 bits long"},
 
75
        {PXE_PGP_RSA_UNSUPPORTED, "pgcrypto does not support RSA keys"},
 
76
        {PXE_PGP_UNKNOWN_PUBALGO, "Unknown public-key encryption algorithm"},
 
77
        {PXE_PGP_WRONG_KEY, "Wrong key"},
 
78
        {PXE_PGP_MULTIPLE_KEYS,
 
79
        "Several keys given - pgcrypto does not handle keyring"},
 
80
        {PXE_PGP_EXPECT_PUBLIC_KEY, "Refusing to encrypt with secret key"},
 
81
        {PXE_PGP_EXPECT_SECRET_KEY, "Cannot decrypt with public key"},
 
82
        {PXE_PGP_NOT_V4_KEYPKT, "Only V4 key packets are supported"},
 
83
        {PXE_PGP_KEYPKT_CORRUPT, "Corrupt key packet"},
 
84
        {PXE_PGP_NO_USABLE_KEY, "No encryption key found"},
 
85
        {PXE_PGP_NEED_SECRET_PSW, "Need password for secret key"},
 
86
        {PXE_PGP_BAD_S2K_MODE, "Bad S2K mode"},
 
87
        {PXE_PGP_UNSUPPORTED_PUBALGO, "Unsupported public key algorithm"},
 
88
        {PXE_PGP_MULTIPLE_SUBKEYS, "Several subkeys not supported"},
 
89
 
 
90
        /* fake this as PXE_PGP_CORRUPT_DATA */
 
91
        {PXE_MBUF_SHORT_READ, "Corrupt data"},
 
92
 
 
93
        {0, NULL},
 
94
};
 
95
 
 
96
const char *
 
97
px_strerror(int err)
 
98
{
 
99
        const struct error_desc *e;
 
100
 
 
101
        for (e = px_err_list; e->desc; e++)
 
102
                if (e->err == err)
 
103
                        return e->desc;
 
104
        return "Bad error code";
 
105
}
 
106
 
 
107
 
 
108
const char *
 
109
px_resolve_alias(const PX_Alias *list, const char *name)
 
110
{
 
111
        while (list->name)
 
112
        {
 
113
                if (pg_strcasecmp(list->alias, name) == 0)
 
114
                        return list->name;
 
115
                list++;
 
116
        }
 
117
        return name;
 
118
}
 
119
 
 
120
static void (*debug_handler) (const char *) = NULL;
 
121
 
 
122
void
 
123
px_set_debug_handler(void (*handler) (const char *))
 
124
{
 
125
        debug_handler = handler;
 
126
}
 
127
 
 
128
void
 
129
px_debug(const char *fmt,...)
 
130
{
 
131
        va_list         ap;
 
132
 
 
133
        va_start(ap, fmt);
 
134
        if (debug_handler)
 
135
        {
 
136
                char            buf[512];
 
137
 
 
138
                vsnprintf(buf, sizeof(buf), fmt, ap);
 
139
                debug_handler(buf);
 
140
        }
 
141
        va_end(ap);
 
142
}
 
143
 
 
144
/*
 
145
 * combo - cipher + padding (+ checksum)
 
146
 */
 
147
 
 
148
static unsigned
 
149
combo_encrypt_len(PX_Combo *cx, unsigned dlen)
 
150
{
 
151
        return dlen + 512;
 
152
}
 
153
 
 
154
static unsigned
 
155
combo_decrypt_len(PX_Combo *cx, unsigned dlen)
 
156
{
 
157
        return dlen;
 
158
}
 
159
 
 
160
static int
 
161
combo_init(PX_Combo *cx, const uint8 *key, unsigned klen,
 
162
                   const uint8 *iv, unsigned ivlen)
 
163
{
 
164
        int                     err;
 
165
        unsigned        ks,
 
166
                                ivs;
 
167
        PX_Cipher  *c = cx->cipher;
 
168
        uint8      *ivbuf = NULL;
 
169
        uint8      *keybuf;
 
170
 
 
171
        ks = px_cipher_key_size(c);
 
172
 
 
173
        ivs = px_cipher_iv_size(c);
 
174
        if (ivs > 0)
 
175
        {
 
176
                ivbuf = px_alloc(ivs);
 
177
                memset(ivbuf, 0, ivs);
 
178
                if (ivlen > ivs)
 
179
                        memcpy(ivbuf, iv, ivs);
 
180
                else
 
181
                        memcpy(ivbuf, iv, ivlen);
 
182
        }
 
183
 
 
184
        if (klen > ks)
 
185
                klen = ks;
 
186
        keybuf = px_alloc(ks);
 
187
        memset(keybuf, 0, ks);
 
188
        memcpy(keybuf, key, klen);
 
189
 
 
190
        err = px_cipher_init(c, keybuf, klen, ivbuf);
 
191
 
 
192
        if (ivbuf)
 
193
                px_free(ivbuf);
 
194
        px_free(keybuf);
 
195
 
 
196
        return err;
 
197
}
 
198
 
 
199
static int
 
200
combo_encrypt(PX_Combo *cx, const uint8 *data, unsigned dlen,
 
201
                          uint8 *res, unsigned *rlen)
 
202
{
 
203
        int                     err = 0;
 
204
        uint8      *bbuf;
 
205
        unsigned        bs,
 
206
                                bpos,
 
207
                                i,
 
208
                                pad;
 
209
 
 
210
        PX_Cipher  *c = cx->cipher;
 
211
 
 
212
        bbuf = NULL;
 
213
        bs = px_cipher_block_size(c);
 
214
 
 
215
        /* encrypt */
 
216
        if (bs > 1)
 
217
        {
 
218
                bbuf = px_alloc(bs * 4);
 
219
                bpos = dlen % bs;
 
220
                *rlen = dlen - bpos;
 
221
                memcpy(bbuf, data + *rlen, bpos);
 
222
 
 
223
                /* encrypt full-block data */
 
224
                if (*rlen)
 
225
                {
 
226
                        err = px_cipher_encrypt(c, data, *rlen, res);
 
227
                        if (err)
 
228
                                goto out;
 
229
                }
 
230
 
 
231
                /* bbuf has now bpos bytes of stuff */
 
232
                if (cx->padding)
 
233
                {
 
234
                        pad = bs - (bpos % bs);
 
235
                        for (i = 0; i < pad; i++)
 
236
                                bbuf[bpos++] = pad;
 
237
                }
 
238
                else if (bpos % bs)
 
239
                {
 
240
                        /* ERROR? */
 
241
                        pad = bs - (bpos % bs);
 
242
                        for (i = 0; i < pad; i++)
 
243
                                bbuf[bpos++] = 0;
 
244
                }
 
245
 
 
246
                /* encrypt the rest - pad */
 
247
                if (bpos)
 
248
                {
 
249
                        err = px_cipher_encrypt(c, bbuf, bpos, res + *rlen);
 
250
                        *rlen += bpos;
 
251
                }
 
252
        }
 
253
        else
 
254
        {
 
255
                /* stream cipher/mode - no pad needed */
 
256
                err = px_cipher_encrypt(c, data, dlen, res);
 
257
                if (err)
 
258
                        goto out;
 
259
                *rlen = dlen;
 
260
        }
 
261
out:
 
262
        if (bbuf)
 
263
                px_free(bbuf);
 
264
 
 
265
        return err;
 
266
}
 
267
 
 
268
static int
 
269
combo_decrypt(PX_Combo *cx, const uint8 *data, unsigned dlen,
 
270
                          uint8 *res, unsigned *rlen)
 
271
{
 
272
        unsigned        bs,
 
273
                                i,
 
274
                                pad;
 
275
        unsigned        pad_ok;
 
276
 
 
277
        PX_Cipher  *c = cx->cipher;
 
278
 
 
279
        /* decide whether zero-length input is allowed */
 
280
        if (dlen == 0)
 
281
        {
 
282
                /* with padding, empty ciphertext is not allowed */
 
283
                if (cx->padding)
 
284
                        return PXE_DECRYPT_FAILED;
 
285
 
 
286
                /* without padding, report empty result */
 
287
                *rlen = 0;
 
288
                return 0;
 
289
        }
 
290
 
 
291
        bs = px_cipher_block_size(c);
 
292
        if (bs > 1 && (dlen % bs) != 0)
 
293
                goto block_error;
 
294
 
 
295
        /* decrypt */
 
296
        *rlen = dlen;
 
297
        px_cipher_decrypt(c, data, dlen, res);
 
298
 
 
299
        /* unpad */
 
300
        if (bs > 1 && cx->padding)
 
301
        {
 
302
                pad = res[*rlen - 1];
 
303
                pad_ok = 0;
 
304
                if (pad > 0 && pad <= bs && pad <= *rlen)
 
305
                {
 
306
                        pad_ok = 1;
 
307
                        for (i = *rlen - pad; i < *rlen; i++)
 
308
                                if (res[i] != pad)
 
309
                                {
 
310
                                        pad_ok = 0;
 
311
                                        break;
 
312
                                }
 
313
                }
 
314
 
 
315
                if (pad_ok)
 
316
                        *rlen -= pad;
 
317
        }
 
318
 
 
319
        return 0;
 
320
 
 
321
block_error:
 
322
        return PXE_NOTBLOCKSIZE;
 
323
}
 
324
 
 
325
static void
 
326
combo_free(PX_Combo *cx)
 
327
{
 
328
        if (cx->cipher)
 
329
                px_cipher_free(cx->cipher);
 
330
        memset(cx, 0, sizeof(*cx));
 
331
        px_free(cx);
 
332
}
 
333
 
 
334
/* PARSER */
 
335
 
 
336
static int
 
337
parse_cipher_name(char *full, char **cipher, char **pad)
 
338
{
 
339
        char       *p,
 
340
                           *p2,
 
341
                           *q;
 
342
 
 
343
        *cipher = full;
 
344
        *pad = NULL;
 
345
 
 
346
        p = strchr(full, '/');
 
347
        if (p != NULL)
 
348
                *p++ = 0;
 
349
        while (p != NULL)
 
350
        {
 
351
                if ((q = strchr(p, '/')) != NULL)
 
352
                        *q++ = 0;
 
353
 
 
354
                if (!*p)
 
355
                {
 
356
                        p = q;
 
357
                        continue;
 
358
                }
 
359
                p2 = strchr(p, ':');
 
360
                if (p2 != NULL)
 
361
                {
 
362
                        *p2++ = 0;
 
363
                        if (!strcmp(p, "pad"))
 
364
                                *pad = p2;
 
365
                        else
 
366
                                return PXE_BAD_OPTION;
 
367
                }
 
368
                else
 
369
                        return PXE_BAD_FORMAT;
 
370
 
 
371
                p = q;
 
372
        }
 
373
        return 0;
 
374
}
 
375
 
 
376
/* provider */
 
377
 
 
378
int
 
379
px_find_combo(const char *name, PX_Combo **res)
 
380
{
 
381
        int                     err;
 
382
        char       *buf,
 
383
                           *s_cipher,
 
384
                           *s_pad;
 
385
 
 
386
        PX_Combo   *cx;
 
387
 
 
388
        cx = px_alloc(sizeof(*cx));
 
389
        memset(cx, 0, sizeof(*cx));
 
390
 
 
391
        buf = px_alloc(strlen(name) + 1);
 
392
        strcpy(buf, name);
 
393
 
 
394
        err = parse_cipher_name(buf, &s_cipher, &s_pad);
 
395
        if (err)
 
396
        {
 
397
                px_free(buf);
 
398
                px_free(cx);
 
399
                return err;
 
400
        }
 
401
 
 
402
        err = px_find_cipher(s_cipher, &cx->cipher);
 
403
        if (err)
 
404
                goto err1;
 
405
 
 
406
        if (s_pad != NULL)
 
407
        {
 
408
                if (!strcmp(s_pad, "pkcs"))
 
409
                        cx->padding = 1;
 
410
                else if (!strcmp(s_pad, "none"))
 
411
                        cx->padding = 0;
 
412
                else
 
413
                        goto err1;
 
414
        }
 
415
        else
 
416
                cx->padding = 1;
 
417
 
 
418
        cx->init = combo_init;
 
419
        cx->encrypt = combo_encrypt;
 
420
        cx->decrypt = combo_decrypt;
 
421
        cx->encrypt_len = combo_encrypt_len;
 
422
        cx->decrypt_len = combo_decrypt_len;
 
423
        cx->free = combo_free;
 
424
 
 
425
        px_free(buf);
 
426
 
 
427
        *res = cx;
 
428
 
 
429
        return 0;
 
430
 
 
431
err1:
 
432
        if (cx->cipher)
 
433
                px_cipher_free(cx->cipher);
 
434
        px_free(cx);
 
435
        px_free(buf);
 
436
        return PXE_NO_CIPHER;
 
437
}