LCOV - code coverage report
Current view: top level - contrib/pgcrypto - pgp-pubdec.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 76.4 % 106 81
Test Date: 2026-03-04 08:14:57 Functions: 100.0 % 5 5
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*
       2              :  * pgp-pubdec.c
       3              :  *    Decrypt public-key encrypted session key.
       4              :  *
       5              :  * Copyright (c) 2005 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/pgp-pubdec.c
      30              :  */
      31              : #include "postgres.h"
      32              : 
      33              : #include "pgp.h"
      34              : #include "px.h"
      35              : 
      36              : /*
      37              :  * padded msg = 02 || PS || 00 || M
      38              :  * PS - pad bytes
      39              :  * M - msg
      40              :  */
      41              : static uint8 *
      42           14 : check_eme_pkcs1_v15(uint8 *data, int len)
      43              : {
      44           14 :     uint8      *data_end = data + len;
      45           14 :     uint8      *p = data;
      46           14 :     int         rnd = 0;
      47              : 
      48           14 :     if (len < 1 + 8 + 1)
      49            0 :         return NULL;
      50              : 
      51           14 :     if (*p++ != 2)
      52            0 :         return NULL;
      53              : 
      54         3127 :     while (p < data_end && *p)
      55              :     {
      56         3113 :         p++;
      57         3113 :         rnd++;
      58              :     }
      59              : 
      60           14 :     if (p == data_end)
      61            0 :         return NULL;
      62           14 :     if (*p != 0)
      63            0 :         return NULL;
      64           14 :     if (rnd < 8)
      65            0 :         return NULL;
      66           14 :     return p + 1;
      67              : }
      68              : 
      69              : /*
      70              :  * secret message: 1 byte algo, sesskey, 2 byte cksum
      71              :  * ignore algo in cksum
      72              :  */
      73              : static int
      74           14 : control_cksum(uint8 *msg, int msglen)
      75              : {
      76              :     int         i;
      77              :     unsigned    my_cksum,
      78              :                 got_cksum;
      79              : 
      80           14 :     if (msglen < 3)
      81            0 :         return PXE_PGP_WRONG_KEY;
      82              : 
      83           14 :     my_cksum = 0;
      84          274 :     for (i = 1; i < msglen - 2; i++)
      85          260 :         my_cksum += msg[i];
      86           14 :     my_cksum &= 0xFFFF;
      87           14 :     got_cksum = ((unsigned) (msg[msglen - 2]) << 8) + msg[msglen - 1];
      88           14 :     if (my_cksum != got_cksum)
      89              :     {
      90            0 :         px_debug("pubenc cksum failed");
      91            0 :         return PXE_PGP_WRONG_KEY;
      92              :     }
      93           14 :     return 0;
      94              : }
      95              : 
      96              : static int
      97            9 : decrypt_elgamal(PGP_PubKey *pk, PullFilter *pkt, PGP_MPI **m_p)
      98              : {
      99              :     int         res;
     100            9 :     PGP_MPI    *c1 = NULL;
     101            9 :     PGP_MPI    *c2 = NULL;
     102              : 
     103            9 :     if (pk->algo != PGP_PUB_ELG_ENCRYPT)
     104            0 :         return PXE_PGP_WRONG_KEY;
     105              : 
     106              :     /* read elgamal encrypted data */
     107            9 :     res = pgp_mpi_read(pkt, &c1);
     108            9 :     if (res < 0)
     109            0 :         goto out;
     110            9 :     res = pgp_mpi_read(pkt, &c2);
     111            9 :     if (res < 0)
     112            0 :         goto out;
     113              : 
     114              :     /* decrypt */
     115            9 :     res = pgp_elgamal_decrypt(pk, c1, c2, m_p);
     116              : 
     117            9 : out:
     118            9 :     pgp_mpi_free(c1);
     119            9 :     pgp_mpi_free(c2);
     120            9 :     return res;
     121              : }
     122              : 
     123              : static int
     124            5 : decrypt_rsa(PGP_PubKey *pk, PullFilter *pkt, PGP_MPI **m_p)
     125              : {
     126              :     int         res;
     127              :     PGP_MPI    *c;
     128              : 
     129            5 :     if (pk->algo != PGP_PUB_RSA_ENCRYPT
     130            4 :         && pk->algo != PGP_PUB_RSA_ENCRYPT_SIGN)
     131            0 :         return PXE_PGP_WRONG_KEY;
     132              : 
     133              :     /* read rsa encrypted data */
     134            5 :     res = pgp_mpi_read(pkt, &c);
     135            5 :     if (res < 0)
     136            0 :         return res;
     137              : 
     138              :     /* decrypt */
     139            5 :     res = pgp_rsa_decrypt(pk, c, m_p);
     140              : 
     141            5 :     pgp_mpi_free(c);
     142            5 :     return res;
     143              : }
     144              : 
     145              : /* key id is missing - user is expected to try all keys */
     146              : static const uint8
     147              :             any_key[] = {0, 0, 0, 0, 0, 0, 0, 0};
     148              : 
     149              : int
     150           15 : pgp_parse_pubenc_sesskey(PGP_Context *ctx, PullFilter *pkt)
     151              : {
     152              :     int         ver;
     153              :     int         algo;
     154              :     int         res;
     155              :     uint8       key_id[8];
     156              :     PGP_PubKey *pk;
     157              :     uint8      *msg;
     158              :     int         msglen;
     159              :     PGP_MPI    *m;
     160              :     unsigned    sess_key_len;
     161              : 
     162           15 :     pk = ctx->pub_key;
     163           15 :     if (pk == NULL)
     164              :     {
     165            0 :         px_debug("no pubkey?");
     166            0 :         return PXE_BUG;
     167              :     }
     168              : 
     169           15 :     GETBYTE(pkt, ver);
     170           15 :     if (ver != 3)
     171              :     {
     172            0 :         px_debug("unknown pubenc_sesskey pkt ver=%d", ver);
     173            0 :         return PXE_PGP_CORRUPT_DATA;
     174              :     }
     175              : 
     176              :     /*
     177              :      * check if keyid's match - user-friendly msg
     178              :      */
     179           15 :     res = pullf_read_fixed(pkt, 8, key_id);
     180           15 :     if (res < 0)
     181            0 :         return res;
     182           15 :     if (memcmp(key_id, any_key, 8) != 0
     183           14 :         && memcmp(key_id, pk->key_id, 8) != 0)
     184              :     {
     185            1 :         px_debug("key_id's does not match");
     186            1 :         return PXE_PGP_WRONG_KEY;
     187              :     }
     188              : 
     189              :     /*
     190              :      * Decrypt
     191              :      */
     192           14 :     GETBYTE(pkt, algo);
     193           14 :     switch (algo)
     194              :     {
     195            9 :         case PGP_PUB_ELG_ENCRYPT:
     196            9 :             res = decrypt_elgamal(pk, pkt, &m);
     197            9 :             break;
     198            5 :         case PGP_PUB_RSA_ENCRYPT:
     199              :         case PGP_PUB_RSA_ENCRYPT_SIGN:
     200            5 :             res = decrypt_rsa(pk, pkt, &m);
     201            5 :             break;
     202            0 :         default:
     203            0 :             res = PXE_PGP_UNKNOWN_PUBALGO;
     204              :     }
     205           14 :     if (res < 0)
     206            0 :         return res;
     207              : 
     208              :     /*
     209              :      * extract message
     210              :      */
     211           14 :     msg = check_eme_pkcs1_v15(m->data, m->bytes);
     212           14 :     if (msg == NULL)
     213              :     {
     214            0 :         px_debug("check_eme_pkcs1_v15 failed");
     215            0 :         res = PXE_PGP_WRONG_KEY;
     216            0 :         goto out;
     217              :     }
     218           14 :     msglen = m->bytes - (msg - m->data);
     219              : 
     220           14 :     res = control_cksum(msg, msglen);
     221           14 :     if (res < 0)
     222            0 :         goto out;
     223              : 
     224           14 :     sess_key_len = msglen - 3;
     225           14 :     if (sess_key_len > PGP_MAX_KEY)
     226              :     {
     227            1 :         px_debug("incorrect session key length=%u", sess_key_len);
     228            1 :         res = PXE_PGP_KEY_TOO_BIG;
     229            1 :         goto out;
     230              :     }
     231              : 
     232              :     /*
     233              :      * got sesskey
     234              :      */
     235           13 :     ctx->cipher_algo = *msg;
     236           13 :     ctx->sess_key_len = sess_key_len;
     237           13 :     memcpy(ctx->sess_key, msg + 1, ctx->sess_key_len);
     238              : 
     239           14 : out:
     240           14 :     pgp_mpi_free(m);
     241           14 :     if (res < 0)
     242            1 :         return res;
     243           13 :     return pgp_expect_packet_end(pkt);
     244              : }
        

Generated by: LCOV version 2.0-1