Header And Logo

PostgreSQL
| The world's most advanced open source database.

pgp-pubdec.c

Go to the documentation of this file.
00001 /*
00002  * pgp-pubdec.c
00003  *    Decrypt public-key encrypted session key.
00004  *
00005  * Copyright (c) 2005 Marko Kreen
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  *
00029  * contrib/pgcrypto/pgp-pubdec.c
00030  */
00031 #include "postgres.h"
00032 
00033 #include "px.h"
00034 #include "mbuf.h"
00035 #include "pgp.h"
00036 
00037 /*
00038  * padded msg = 02 || PS || 00 || M
00039  * PS - pad bytes
00040  * M - msg
00041  */
00042 static uint8 *
00043 check_eme_pkcs1_v15(uint8 *data, int len)
00044 {
00045     uint8      *data_end = data + len;
00046     uint8      *p = data;
00047     int         rnd = 0;
00048 
00049     if (len < 1 + 8 + 1)
00050         return NULL;
00051 
00052     if (*p++ != 2)
00053         return NULL;
00054 
00055     while (p < data_end && *p)
00056     {
00057         p++;
00058         rnd++;
00059     }
00060 
00061     if (p == data_end)
00062         return NULL;
00063     if (*p != 0)
00064         return NULL;
00065     if (rnd < 8)
00066         return NULL;
00067     return p + 1;
00068 }
00069 
00070 /*
00071  * secret message: 1 byte algo, sesskey, 2 byte cksum
00072  * ignore algo in cksum
00073  */
00074 static int
00075 control_cksum(uint8 *msg, int msglen)
00076 {
00077     int         i;
00078     unsigned    my_cksum,
00079                 got_cksum;
00080 
00081     if (msglen < 3)
00082         return PXE_PGP_WRONG_KEY;
00083 
00084     my_cksum = 0;
00085     for (i = 1; i < msglen - 2; i++)
00086         my_cksum += msg[i];
00087     my_cksum &= 0xFFFF;
00088     got_cksum = ((unsigned) (msg[msglen - 2]) << 8) + msg[msglen - 1];
00089     if (my_cksum != got_cksum)
00090     {
00091         px_debug("pubenc cksum failed");
00092         return PXE_PGP_WRONG_KEY;
00093     }
00094     return 0;
00095 }
00096 
00097 static int
00098 decrypt_elgamal(PGP_PubKey *pk, PullFilter *pkt, PGP_MPI **m_p)
00099 {
00100     int         res;
00101     PGP_MPI    *c1 = NULL;
00102     PGP_MPI    *c2 = NULL;
00103 
00104     if (pk->algo != PGP_PUB_ELG_ENCRYPT)
00105         return PXE_PGP_WRONG_KEY;
00106 
00107     /* read elgamal encrypted data */
00108     res = pgp_mpi_read(pkt, &c1);
00109     if (res < 0)
00110         goto out;
00111     res = pgp_mpi_read(pkt, &c2);
00112     if (res < 0)
00113         goto out;
00114 
00115     /* decrypt */
00116     res = pgp_elgamal_decrypt(pk, c1, c2, m_p);
00117 
00118 out:
00119     pgp_mpi_free(c1);
00120     pgp_mpi_free(c2);
00121     return res;
00122 }
00123 
00124 static int
00125 decrypt_rsa(PGP_PubKey *pk, PullFilter *pkt, PGP_MPI **m_p)
00126 {
00127     int         res;
00128     PGP_MPI    *c;
00129 
00130     if (pk->algo != PGP_PUB_RSA_ENCRYPT
00131         && pk->algo != PGP_PUB_RSA_ENCRYPT_SIGN)
00132         return PXE_PGP_WRONG_KEY;
00133 
00134     /* read rsa encrypted data */
00135     res = pgp_mpi_read(pkt, &c);
00136     if (res < 0)
00137         return res;
00138 
00139     /* decrypt */
00140     res = pgp_rsa_decrypt(pk, c, m_p);
00141 
00142     pgp_mpi_free(c);
00143     return res;
00144 }
00145 
00146 /* key id is missing - user is expected to try all keys */
00147 static const uint8
00148             any_key[] = {0, 0, 0, 0, 0, 0, 0, 0};
00149 
00150 int
00151 pgp_parse_pubenc_sesskey(PGP_Context *ctx, PullFilter *pkt)
00152 {
00153     int         ver;
00154     int         algo;
00155     int         res;
00156     uint8       key_id[8];
00157     PGP_PubKey *pk;
00158     uint8      *msg;
00159     int         msglen;
00160     PGP_MPI    *m;
00161 
00162     pk = ctx->pub_key;
00163     if (pk == NULL)
00164     {
00165         px_debug("no pubkey?");
00166         return PXE_BUG;
00167     }
00168 
00169     GETBYTE(pkt, ver);
00170     if (ver != 3)
00171     {
00172         px_debug("unknown pubenc_sesskey pkt ver=%d", ver);
00173         return PXE_PGP_CORRUPT_DATA;
00174     }
00175 
00176     /*
00177      * check if keyid's match - user-friendly msg
00178      */
00179     res = pullf_read_fixed(pkt, 8, key_id);
00180     if (res < 0)
00181         return res;
00182     if (memcmp(key_id, any_key, 8) != 0
00183         && memcmp(key_id, pk->key_id, 8) != 0)
00184     {
00185         px_debug("key_id's does not match");
00186         return PXE_PGP_WRONG_KEY;
00187     }
00188 
00189     /*
00190      * Decrypt
00191      */
00192     GETBYTE(pkt, algo);
00193     switch (algo)
00194     {
00195         case PGP_PUB_ELG_ENCRYPT:
00196             res = decrypt_elgamal(pk, pkt, &m);
00197             break;
00198         case PGP_PUB_RSA_ENCRYPT:
00199         case PGP_PUB_RSA_ENCRYPT_SIGN:
00200             res = decrypt_rsa(pk, pkt, &m);
00201             break;
00202         default:
00203             res = PXE_PGP_UNKNOWN_PUBALGO;
00204     }
00205     if (res < 0)
00206         return res;
00207 
00208     /*
00209      * extract message
00210      */
00211     msg = check_eme_pkcs1_v15(m->data, m->bytes);
00212     if (msg == NULL)
00213     {
00214         px_debug("check_eme_pkcs1_v15 failed");
00215         res = PXE_PGP_WRONG_KEY;
00216         goto out;
00217     }
00218     msglen = m->bytes - (msg - m->data);
00219 
00220     res = control_cksum(msg, msglen);
00221     if (res < 0)
00222         goto out;
00223 
00224     /*
00225      * got sesskey
00226      */
00227     ctx->cipher_algo = *msg;
00228     ctx->sess_key_len = msglen - 3;
00229     memcpy(ctx->sess_key, msg + 1, ctx->sess_key_len);
00230 
00231 out:
00232     pgp_mpi_free(m);
00233     if (res < 0)
00234         return res;
00235     return pgp_expect_packet_end(pkt);
00236 }