Skip to content

Commit

Permalink
API: Basic support for OpenPGP public keys
Browse files Browse the repository at this point in the history
The code publishes the basic API needed to work with OpenPGP public keys.
- `Key` class representing one key and its basic attributes
- static `Key::fromFd` method for loading keys from the file descriptor
- function `importKeyToPubring` to import key into a keyring
- function `keyidsFromPubring` a list of key IDs in the keyring
  • Loading branch information
jrohel committed Aug 23, 2023
1 parent 20b0724 commit 1b6a376
Show file tree
Hide file tree
Showing 8 changed files with 243 additions and 107 deletions.
4 changes: 2 additions & 2 deletions VERSION.cmake
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
set (DEFAULT_LIBDNF_MAJOR_VERSION 0)
set (DEFAULT_LIBDNF_MINOR_VERSION 70)
set (DEFAULT_LIBDNF_MICRO_VERSION 2)
set (DEFAULT_LIBDNF_MINOR_VERSION 71)
set (DEFAULT_LIBDNF_MICRO_VERSION 0)

if(DEFINED LIBDNF_MAJOR_VERSION)
if(NOT ${DEFAULT_LIBDNF_MAJOR_VERSION} STREQUAL ${LIBDNF_MAJOR_VERSION})
Expand Down
6 changes: 6 additions & 0 deletions bindings/swig/repo.i
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

%{
// make SWIG wrap following headers
#include "libdnf/repo/Crypto.hpp"
#include "libdnf/repo/Repo.hpp"
%}

Expand Down Expand Up @@ -81,6 +82,11 @@
int64_t byteRangeStart, int64_t byteRangeEnd, PackageTargetCB * callbacks,
const char * httpHeaders[] = nullptr);

%ignore std::vector<libdnf::Key>::vector(size_type);
%ignore std::vector<libdnf::Key>::resize;
%template(VectorKey) std::vector<libdnf::Key>;
%include "libdnf/repo/Crypto.hpp"

%feature("director") libdnf::RepoCB;
%ignore libdnf::PackageTarget::PackageTarget(const PackageTarget & src);
%feature("director") libdnf::PackageTargetCB;
Expand Down
4 changes: 2 additions & 2 deletions libdnf.spec
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
%global dnf_conflict 4.11.0
%global swig_version 3.0.12
%global libdnf_major_version 0
%global libdnf_minor_version 70
%global libdnf_micro_version 2
%global libdnf_minor_version 71
%global libdnf_micro_version 0

%define __cmake_in_source_build 1

Expand Down
2 changes: 2 additions & 0 deletions libdnf/repo/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ add_subdirectory(solvable)

set(REPO_SOURCES
${REPO_SOURCES}
${CMAKE_CURRENT_SOURCE_DIR}/Crypto.cpp
${CMAKE_CURRENT_SOURCE_DIR}/DependencySplitter.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Repo.cpp
PARENT_SCOPE
)

set(REPO_HEADERS
${REPO_HEADERS}
${CMAKE_CURRENT_SOURCE_DIR}/Crypto.hpp
${CMAKE_CURRENT_SOURCE_DIR}/Repo.hpp
PARENT_SCOPE
)
168 changes: 168 additions & 0 deletions libdnf/repo/Crypto.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/*
* Copyright (C) 2023 Red Hat, Inc.
*
* Licensed under the GNU Lesser General Public License Version 2.1
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "Crypto.hpp"
#include "Repo.hpp"

#include "../dnf-utils.h"
#include "bgettext/bgettext-lib.h"
#include "tinyformat/tinyformat.hpp"
#include "utils.hpp"

#include <librepo/librepo.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>

#include <glib.h>

#include <utility>

namespace libdnf {

static void throwException(GError * err)
{
LrException ex(err->code, err->message);
g_error_free(err);
throw ex;
}

Key::Key(const void * key, const void * subkey)
: id{lr_gpg_subkey_get_id(static_cast<const LrGpgSubkey *>(subkey))},
fingerprint{lr_gpg_subkey_get_fingerprint(static_cast<const LrGpgSubkey *>(subkey))},
timestamp{lr_gpg_subkey_get_timestamp(static_cast<const LrGpgSubkey *>(subkey))},
rawKey{lr_gpg_key_get_raw_key(static_cast<const LrGpgKey *>(key))}
{
auto * userid_c = lr_gpg_key_get_userids(static_cast<const LrGpgKey *>(key))[0];
userid = userid_c ? userid_c : "";
}

const std::string & Key::getId() const noexcept
{
return id;
}

const std::string & Key::getUserId() const noexcept
{
return userid;
}

const std::string & Key::getFingerprint() const noexcept
{
return fingerprint;
}

long int Key::getTimestamp() const noexcept
{
return timestamp;
}

const std::string & Key::getRawKey() const noexcept
{
return rawKey;
}

const std::string & Key::getUrl() const noexcept
{
return url;
}

void Key::setUrl(std::string url)
{
this->url = std::move(url);
}

std::vector<Key> Key::fromFd(int fd)
{
std::vector<Key> keyInfos;

char tmpdir[] = "/tmp/tmpdir.XXXXXX";
if (!mkdtemp(tmpdir)) {
const char * errTxt = strerror(errno);
throw RepoError(tfm::format(_("Cannot create repo temporary directory \"%s\": %s"),
tmpdir, errTxt));
}
Finalizer tmpDirRemover([&tmpdir](){
dnf_remove_recursive(tmpdir, NULL);
});

GError * err = NULL;
if (!lr_gpg_import_key_from_fd(fd, tmpdir, &err)) {
throwException(err);
}

std::unique_ptr<LrGpgKey, decltype(&lr_gpg_keys_free)> lr_keys{
lr_gpg_list_keys(TRUE, tmpdir, &err), &lr_gpg_keys_free};
if (err) {
throwException(err);
}

for (const auto * lr_key = lr_keys.get(); lr_key; lr_key = lr_gpg_key_get_next(lr_key)) {
for (const auto * lr_subkey = lr_gpg_key_get_subkeys(lr_key); lr_subkey;
lr_subkey = lr_gpg_subkey_get_next(lr_subkey)) {
// get first signing subkey
if (lr_gpg_subkey_get_can_sign(lr_subkey)) {
keyInfos.emplace_back(Key(lr_key, lr_subkey));
break;
}
}
}

return keyInfos;
}

void importKeyToPubring(const std::string & rawKey, const std::string & pubringDir)
{
GError * err = NULL;
if (!lr_gpg_import_key_from_memory(
rawKey.c_str(), rawKey.size(), pubringDir.c_str(), &err)) {
throwException(err);
}
}

std::vector<std::string> keyidsFromPubring(const std::string & pubringDir)
{
std::vector<std::string> keyids;

struct stat sb;
if (stat(pubringDir.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)) {
GError * err = NULL;
std::unique_ptr<LrGpgKey, decltype(&lr_gpg_keys_free)> lr_keys{
lr_gpg_list_keys(FALSE, pubringDir.c_str(), &err), &lr_gpg_keys_free};
if (err) {
throwException(err);
}

for (const auto * lr_key = lr_keys.get(); lr_key; lr_key = lr_gpg_key_get_next(lr_key)) {
for (const auto * lr_subkey = lr_gpg_key_get_subkeys(lr_key); lr_subkey;
lr_subkey = lr_gpg_subkey_get_next(lr_subkey)) {
// get first signing subkey
if (lr_gpg_subkey_get_can_sign(lr_subkey)) {
keyids.emplace_back(lr_gpg_subkey_get_id(lr_subkey));
break;
}
}
}
}

return keyids;
}

}
57 changes: 57 additions & 0 deletions libdnf/repo/Crypto.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2023 Red Hat, Inc.
*
* Licensed under the GNU Lesser General Public License Version 2.1
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#ifndef _LIBDNF_CRYPTO_HPP
#define _LIBDNF_CRYPTO_HPP

#include <string>
#include <vector>

namespace libdnf {

class Key {
public:
static std::vector<Key> fromFd(int fd);

const std::string & getId() const noexcept;
const std::string & getUserId() const noexcept;
const std::string & getFingerprint() const noexcept;
long int getTimestamp() const noexcept;
const std::string & getRawKey() const noexcept;
const std::string & getUrl() const noexcept;
void setUrl(std::string url);

private:
Key(const void * key, const void * subkey);

std::string id;
std::string fingerprint;
std::string userid;
long int timestamp;
std::string rawKey;
std::string url;
};

void importKeyToPubring(const std::string & rawKey, const std::string & pubringDir);
std::vector<std::string> keyidsFromPubring(const std::string & pubringDir);

}

#endif
21 changes: 1 addition & 20 deletions libdnf/repo/Repo-private.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#ifndef _LIBDNF_REPO_PRIVATE_HPP
#define _LIBDNF_REPO_PRIVATE_HPP

#include "Crypto.hpp"
#include "Repo.hpp"
#include "../dnf-utils.h"
#include "../hy-iutil.h"
Expand Down Expand Up @@ -78,26 +79,6 @@ namespace libdnf {

typedef ::Repo LibsolvRepo;

class Key {
public:
Key(const LrGpgKey * key, const LrGpgSubkey * subkey);

const std::string & getId() const noexcept { return id; }
const std::string & getUserId() const noexcept { return userid; }
const std::string & getFingerprint() const noexcept { return fingerprint; }
long int getTimestamp() const noexcept { return timestamp; }
const std::string & getRawKey() const noexcept { return rawKey; }

std::string url;

private:
std::string id;
std::string fingerprint;
std::string userid;
long int timestamp;
std::string rawKey;
};

class Repo::Impl {
public:
Impl(Repo & owner, const std::string & id, Type type, std::unique_ptr<ConfigRepo> && conf);
Expand Down
Loading

0 comments on commit 1b6a376

Please sign in to comment.