From 9f2a3023f8088800efd3a0abeb32ed5117be4442 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 6 Sep 2009 19:32:56 -0500 Subject: Add base64 algorithms from PolarSSL to libalpm We will need these for GPG functionality (decoding the base64 encoded signature stored in the databases). Signed-off-by: Dan McGee Signed-off-by: Allan McRae --- lib/libalpm/Makefile.am | 1 + lib/libalpm/base64.c | 190 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/libalpm/base64.h | 68 +++++++++++++++++ 3 files changed, 259 insertions(+) create mode 100644 lib/libalpm/base64.c create mode 100644 lib/libalpm/base64.h diff --git a/lib/libalpm/Makefile.am b/lib/libalpm/Makefile.am index 1bda5714..7c411b2c 100644 --- a/lib/libalpm/Makefile.am +++ b/lib/libalpm/Makefile.am @@ -25,6 +25,7 @@ libalpm_la_SOURCES = \ alpm.h alpm.c \ alpm_list.h alpm_list.c \ backup.h backup.c \ + base64.h base64.c \ be_local.c \ be_package.c \ be_sync.c \ diff --git a/lib/libalpm/base64.c b/lib/libalpm/base64.c new file mode 100644 index 00000000..fa8bec5c --- /dev/null +++ b/lib/libalpm/base64.c @@ -0,0 +1,190 @@ +/* + * RFC 1521 base64 encoding/decoding + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +/* + * Pacman Notes: + * + * Taken from the PolarSSL project at www.polarssl.org under terms of the + * GPL. This is from version 0.14.2 of the library, and has been modified + * as following, which may be helpful for future updates: + * * remove "polarssl/config.h" include + * * change include from "polarssl/base64.h" to "base64.h" + * * removal of SELF_TEST code + */ + +#include "base64.h" + +static const unsigned char base64_enc_map[64] = +{ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', + 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', + 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '+', '/' +}; + +static const unsigned char base64_dec_map[128] = +{ + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 62, 127, 127, 127, 63, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 127, 127, + 127, 64, 127, 127, 127, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 127, 127, 127, 127, 127, 127, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 127, 127, 127, 127, 127 +}; + +/* + * Encode a buffer into base64 format + */ +int base64_encode( unsigned char *dst, int *dlen, + const unsigned char *src, int slen ) +{ + int i, n; + int C1, C2, C3; + unsigned char *p; + + if( slen == 0 ) + return( 0 ); + + n = (slen << 3) / 6; + + switch( (slen << 3) - (n * 6) ) + { + case 2: n += 3; break; + case 4: n += 2; break; + default: break; + } + + if( *dlen < n + 1 ) + { + *dlen = n + 1; + return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL ); + } + + n = (slen / 3) * 3; + + for( i = 0, p = dst; i < n; i += 3 ) + { + C1 = *src++; + C2 = *src++; + C3 = *src++; + + *p++ = base64_enc_map[(C1 >> 2) & 0x3F]; + *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F]; + *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F]; + *p++ = base64_enc_map[C3 & 0x3F]; + } + + if( i < slen ) + { + C1 = *src++; + C2 = ((i + 1) < slen) ? *src++ : 0; + + *p++ = base64_enc_map[(C1 >> 2) & 0x3F]; + *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F]; + + if( (i + 1) < slen ) + *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F]; + else *p++ = '='; + + *p++ = '='; + } + + *dlen = p - dst; + *p = 0; + + return( 0 ); +} + +/* + * Decode a base64-formatted buffer + */ +int base64_decode( unsigned char *dst, int *dlen, + const unsigned char *src, int slen ) +{ + int i, j, n; + unsigned long x; + unsigned char *p; + + for( i = j = n = 0; i < slen; i++ ) + { + if( ( slen - i ) >= 2 && + src[i] == '\r' && src[i + 1] == '\n' ) + continue; + + if( src[i] == '\n' ) + continue; + + if( src[i] == '=' && ++j > 2 ) + return( POLARSSL_ERR_BASE64_INVALID_CHARACTER ); + + if( src[i] > 127 || base64_dec_map[src[i]] == 127 ) + return( POLARSSL_ERR_BASE64_INVALID_CHARACTER ); + + if( base64_dec_map[src[i]] < 64 && j != 0 ) + return( POLARSSL_ERR_BASE64_INVALID_CHARACTER ); + + n++; + } + + if( n == 0 ) + return( 0 ); + + n = ((n * 6) + 7) >> 3; + + if( *dlen < n ) + { + *dlen = n; + return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL ); + } + + for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ ) + { + if( *src == '\r' || *src == '\n' ) + continue; + + j -= ( base64_dec_map[*src] == 64 ); + x = (x << 6) | ( base64_dec_map[*src] & 0x3F ); + + if( ++n == 4 ) + { + n = 0; + if( j > 0 ) *p++ = (unsigned char)( x >> 16 ); + if( j > 1 ) *p++ = (unsigned char)( x >> 8 ); + if( j > 2 ) *p++ = (unsigned char)( x ); + } + } + + *dlen = p - dst; + + return( 0 ); +} diff --git a/lib/libalpm/base64.h b/lib/libalpm/base64.h new file mode 100644 index 00000000..0ae9612c --- /dev/null +++ b/lib/libalpm/base64.h @@ -0,0 +1,68 @@ +/** + * \file base64.h + * + * Copyright (C) 2006-2010, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _BASE64_H +#define _BASE64_H + +#define POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL 0x0010 +#define POLARSSL_ERR_BASE64_INVALID_CHARACTER 0x0012 + +/** + * \brief Encode a buffer into base64 format + * + * \param dst destination buffer + * \param dlen size of the buffer + * \param src source buffer + * \param slen amount of data to be encoded + * + * \return 0 if successful, or POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL. + * *dlen is always updated to reflect the amount + * of data that has (or would have) been written. + * + * \note Call this function with *dlen = 0 to obtain the + * required buffer size in *dlen + */ +int base64_encode( unsigned char *dst, int *dlen, + const unsigned char *src, int slen ); + +/** + * \brief Decode a base64-formatted buffer + * + * \param dst destination buffer + * \param dlen size of the buffer + * \param src source buffer + * \param slen amount of data to be decoded + * + * \return 0 if successful, POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL, or + * POLARSSL_ERR_BASE64_INVALID_DATA if the input data is not + * correct. *dlen is always updated to reflect the amount + * of data that has (or would have) been written. + * + * \note Call this function with *dlen = 0 to obtain the + * required buffer size in *dlen + */ +int base64_decode( unsigned char *dst, int *dlen, + const unsigned char *src, int slen ); + +#endif /* base64.h */ -- cgit v1.2.3-70-g09d2 From 60159c2e77a499067e0b294fc9c6c182f225bee2 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Mon, 2 Jun 2008 15:16:00 -0500 Subject: Allow PGP signature to be read from sync database Add a new field to the package struct to hold PGP information and instruct db_read to pick it up from the database. It is currently unused internally but this is the first step. Due to the fact that we store the PGP sig as binary data, we need to store both the data and the length so we have a small utility struct to assist us. Signed-off-by: Dan McGee Signed-off-by: Allan McRae --- lib/libalpm/alpm.h | 2 ++ lib/libalpm/package.c | 39 +++++++++++++++++++++++++++++++++++++++ lib/libalpm/package.h | 12 ++++++++++++ 3 files changed, 53 insertions(+) diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index 0b80506f..44722c1c 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -45,6 +45,7 @@ extern "C" { typedef struct __pmdb_t pmdb_t; typedef struct __pmpkg_t pmpkg_t; +typedef struct __pmpgpsig_t pmpgpsig_t; typedef struct __pmdelta_t pmdelta_t; typedef struct __pmgrp_t pmgrp_t; typedef struct __pmtrans_t pmtrans_t; @@ -215,6 +216,7 @@ time_t alpm_pkg_get_builddate(pmpkg_t *pkg); time_t alpm_pkg_get_installdate(pmpkg_t *pkg); const char *alpm_pkg_get_packager(pmpkg_t *pkg); const char *alpm_pkg_get_md5sum(pmpkg_t *pkg); +const pmpgpsig_t *alpm_pkg_get_pgpsig(pmpkg_t *pkg); const char *alpm_pkg_get_arch(pmpkg_t *pkg); off_t alpm_pkg_get_size(pmpkg_t *pkg); off_t alpm_pkg_get_isize(pmpkg_t *pkg); diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c index 445653ec..257b2aeb 100644 --- a/lib/libalpm/package.c +++ b/lib/libalpm/package.c @@ -40,6 +40,7 @@ #include "delta.h" #include "handle.h" #include "deps.h" +#include "base64.h" /** \addtogroup alpm_packages Package Functions * @brief Functions to manipulate libalpm packages @@ -201,6 +202,42 @@ const char SYMEXPORT *alpm_pkg_get_md5sum(pmpkg_t *pkg) return pkg->ops->get_md5sum(pkg); } +static int decode_pgpsig(pmpkg_t *pkg) { + int len = strlen(pkg->pgpsig.encdata); + const unsigned char *usline = (const unsigned char*)pkg->pgpsig.encdata; + int destlen = 0; + /* get the necessary size for the buffer by passing 0 */ + int ret = base64_decode(NULL, &destlen, usline, len); + /* alloc our memory and repeat the call to decode */ + MALLOC(pkg->pgpsig.rawdata, (size_t)destlen, goto error); + ret = base64_decode(pkg->pgpsig.rawdata, &destlen, usline, len); + pkg->pgpsig.rawlen = destlen; + if(ret != 0) { + goto error; + } + + FREE(pkg->pgpsig.encdata); + return 0; + +error: + FREE(pkg->pgpsig.rawdata); + pkg->pgpsig.rawlen = 0; + return 1; +} + +const pmpgpsig_t SYMEXPORT *alpm_pkg_get_pgpsig(pmpkg_t *pkg) +{ + ALPM_LOG_FUNC; + + /* Sanity checks */ + ASSERT(pkg != NULL, RET_ERR(PM_ERR_WRONG_ARGS, NULL)); + + if(pkg->pgpsig.rawdata == NULL && pkg->pgpsig.encdata != NULL) { + decode_pgpsig(pkg); + } + return &(pkg->pgpsig); +} + const char SYMEXPORT *alpm_pkg_get_arch(pmpkg_t *pkg) { return pkg->ops->get_arch(pkg); @@ -463,6 +500,8 @@ void _alpm_pkg_free(pmpkg_t *pkg) FREE(pkg->url); FREE(pkg->packager); FREE(pkg->md5sum); + FREE(pkg->pgpsig.encdata); + FREE(pkg->pgpsig.rawdata); FREE(pkg->arch); FREELIST(pkg->licenses); FREELIST(pkg->replaces); diff --git a/lib/libalpm/package.h b/lib/libalpm/package.h index b161d5f1..25ed5cf4 100644 --- a/lib/libalpm/package.h +++ b/lib/libalpm/package.h @@ -87,6 +87,16 @@ struct pkg_operations { */ extern struct pkg_operations default_pkg_ops; +struct __pmpgpsig_t { + /* we will either store the encoded data or the raw data- + * this way we can decode on an as-needed basis since most + * operations won't require the overhead of base64 decodes + * on all packages in a sync repository. */ + char *encdata; + size_t rawlen; + unsigned char *rawdata; +}; + struct __pmpkg_t { unsigned long name_hash; char *filename; @@ -98,6 +108,8 @@ struct __pmpkg_t { char *md5sum; char *arch; + pmpgpsig_t pgpsig; + time_t builddate; time_t installdate; -- cgit v1.2.3-70-g09d2 From 39da0198cd132bbb72be234b584bc62c88db33b6 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 3 Jun 2008 21:22:49 -0500 Subject: Add PGP signature support to pactest Allow pkg.pgpsig to end up in the created sync databases. Signed-off-by: Dan McGee --- test/pacman/pmdb.py | 4 ++++ test/pacman/pmpkg.py | 1 + 2 files changed, 5 insertions(+) diff --git a/test/pacman/pmdb.py b/test/pacman/pmdb.py index b31498a7..fefb135a 100755 --- a/test/pacman/pmdb.py +++ b/test/pacman/pmdb.py @@ -150,6 +150,8 @@ class pmdb(object): pkg.size = int(fd.readline().strip("\n")) elif line == "%MD5SUM%": pkg.md5sum = fd.readline().strip("\n") + elif line == "%PGPSIG%": + pkg.pgpsig = fd.readline().strip("\n") elif line == "%REPLACES%": pkg.replaces = _getsection(fd) elif line == "%DEPENDS%": @@ -241,6 +243,8 @@ class pmdb(object): data.append(_mksection("CSIZE", pkg.csize)) if pkg.md5sum: data.append(_mksection("MD5SUM", pkg.md5sum)) + if pkg.pgpsig: + data.append(_mksection("PGPSIG", pkg.pgpsig)) if data: data.append("") filename = os.path.join(path, "desc") diff --git a/test/pacman/pmpkg.py b/test/pacman/pmpkg.py index 73156ab2..ec51e5d4 100755 --- a/test/pacman/pmpkg.py +++ b/test/pacman/pmpkg.py @@ -47,6 +47,7 @@ class pmpkg(object): self.csize = 0 self.reason = 0 self.md5sum = "" # sync only + self.pgpsig = "" # sync only self.replaces = [] self.depends = [] self.optdepends = [] -- cgit v1.2.3-70-g09d2 From 88746ec067c00a9e81f4323aa857a5bcf37258ad Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 7 Dec 2008 13:01:28 -0600 Subject: Read in .sig files when opening a package file If a .sig file sits side-by-side on the filesystem with a package archive, read it in during the package struct creation process so we can verify it at a later time if necessary. Signed-off-by: Dan McGee Signed-off-by: Allan McRae --- lib/libalpm/be_package.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/lib/libalpm/be_package.c b/lib/libalpm/be_package.c index fbd2c0c7..e8d26aa7 100644 --- a/lib/libalpm/be_package.c +++ b/lib/libalpm/be_package.c @@ -251,11 +251,57 @@ static pmpkg_t *pkg_load(const char *pkgfile, int full) RET_ERR(PM_ERR_WRONG_ARGS, NULL); } - if(stat(pkgfile, &st) != 0) { + /* attempt to stat the package file, ensure it exists */ + if(stat(pkgfile, &st) == 0) { + char *pgpfile; + + newpkg = _alpm_pkg_new(); + if(newpkg == NULL) { + RET_ERR(PM_ERR_MEMORY, NULL); + } + newpkg->filename = strdup(pkgfile); + newpkg->size = st.st_size; + + /* look around for a PGP signature file; load if available */ + MALLOC(pgpfile, strlen(pkgfile) + 5, RET_ERR(PM_ERR_MEMORY, NULL)); + sprintf(pgpfile, "%s.sig", pkgfile); + if(access(pgpfile, R_OK) == 0) { + FILE *f; + long bytes; + size_t bytes_read; + f = fopen(pgpfile, "rb"); + fseek(f, 0L, SEEK_END); + bytes = ftell(f); + fseek(f, 0L, SEEK_SET); + /* don't read the file in if it is obviously not the size of a sig */ + if(bytes == 72) { + CALLOC(newpkg->pgpsig.rawdata, bytes, sizeof(char), + RET_ERR(PM_ERR_MEMORY, NULL)); + bytes_read = fread(newpkg->pgpsig.rawdata, sizeof(char), bytes, f); + if(bytes_read == (size_t)bytes) { + newpkg->pgpsig.rawlen = bytes; + _alpm_log(PM_LOG_DEBUG, + "loaded package .sig file, location %s\n", pgpfile); + } else { + _alpm_log(PM_LOG_WARNING, _("Failed reading PGP signature file for %s"), + pkgfile); + } + } else { + _alpm_log(PM_LOG_WARNING, _("PGP signature file for %s was abnormal" + " (had length %ld), skipping\n"), pkgfile, bytes); + } + fclose(f); + } else { + _alpm_log(PM_LOG_DEBUG, "no package signature file found\n"); + } + FREE(pgpfile); + } else { + /* couldn't stat the pkgfile, return an error */ RET_ERR(PM_ERR_PKG_OPEN, NULL); } if((archive = archive_read_new()) == NULL) { + alpm_pkg_free(newpkg); RET_ERR(PM_ERR_LIBARCHIVE, NULL); } @@ -264,6 +310,7 @@ static pmpkg_t *pkg_load(const char *pkgfile, int full) if (archive_read_open_filename(archive, pkgfile, ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) { + alpm_pkg_free(newpkg); RET_ERR(PM_ERR_PKG_OPEN, NULL); } -- cgit v1.2.3-70-g09d2 From cedc63375758cf1c2a821dd5a78d960b34b44f28 Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Sun, 7 Dec 2008 11:58:44 -0600 Subject: Add a few pactests for PGP integration Signed-off-by: Dan McGee --- test/pacman/tests/sign001.py | 9 +++++++++ test/pacman/tests/smoke004.py | 11 +++++++++++ 2 files changed, 20 insertions(+) create mode 100644 test/pacman/tests/sign001.py create mode 100644 test/pacman/tests/smoke004.py diff --git a/test/pacman/tests/sign001.py b/test/pacman/tests/sign001.py new file mode 100644 index 00000000..447cea1e --- /dev/null +++ b/test/pacman/tests/sign001.py @@ -0,0 +1,9 @@ +self.description = "Add a signature to a package DB" + +sp = pmpkg("pkg1") +sp.pgpsig = "asdfasdfsdfasdfsdafasdfsdfasd" +self.addpkg2db("sync", sp) + +self.args = "-Ss" + +self.addrule("PACMAN_RETCODE=0") diff --git a/test/pacman/tests/smoke004.py b/test/pacman/tests/smoke004.py new file mode 100644 index 00000000..1f9b883d --- /dev/null +++ b/test/pacman/tests/smoke004.py @@ -0,0 +1,11 @@ +self.description = "Read a package DB with several PGP signatures" + +for i in range(1000): + sp = pmpkg("pkg%03d" % i) + sp.desc = "test description for package %d" % i + sp.pgpsig = "asdfasdfsdfasdfsdafasdfsdfasd" + self.addpkg2db("sync", sp) + +self.args = "-Ss" + +self.addrule("PACMAN_RETCODE=0") -- cgit v1.2.3-70-g09d2