Blame lang/cpp/src/gpggencardkeyinteractor.cpp

Packit Service 672cf4
/*
Packit Service 672cf4
  gpggencardkeyinteractor.cpp - Edit Interactor to generate a key on a card
Packit Service 672cf4
  Copyright (C) 2017 by Bundesamt für Sicherheit in der Informationstechnik
Packit Service 672cf4
  Software engineering by Intevation GmbH
Packit Service 672cf4
Packit Service 672cf4
  This file is part of GPGME++.
Packit Service 672cf4
Packit Service 672cf4
  GPGME++ is free software; you can redistribute it and/or
Packit Service 672cf4
  modify it under the terms of the GNU Library General Public
Packit Service 672cf4
  License as published by the Free Software Foundation; either
Packit Service 672cf4
  version 2 of the License, or (at your option) any later version.
Packit Service 672cf4
Packit Service 672cf4
  GPGME++ is distributed in the hope that it will be useful,
Packit Service 672cf4
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 672cf4
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 672cf4
  GNU Library General Public License for more details.
Packit Service 672cf4
Packit Service 672cf4
  You should have received a copy of the GNU Library General Public License
Packit Service 672cf4
  along with GPGME++; see the file COPYING.LIB.  If not, write to the
Packit Service 672cf4
  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Packit Service 672cf4
  Boston, MA 02110-1301, USA.
Packit Service 672cf4
*/
Packit Service 672cf4
Packit Service 672cf4
#ifdef HAVE_CONFIG_H
Packit Service 672cf4
 #include "config.h"
Packit Service 672cf4
#endif
Packit Service 672cf4
Packit Service 672cf4
#include "gpggencardkeyinteractor.h"
Packit Service 672cf4
Packit Service 672cf4
#include "error.h"
Packit Service 672cf4
Packit Service 672cf4
#include <gpgme.h>
Packit Service 672cf4
Packit Service 672cf4
using namespace GpgME;
Packit Service 672cf4
Packit Service 672cf4
class GpgGenCardKeyInteractor::Private
Packit Service 672cf4
{
Packit Service 672cf4
public:
Packit Service 6c01f9
    Private() : keysize(2048), backup(false)
Packit Service 672cf4
    {
Packit Service 672cf4
Packit Service 672cf4
    }
Packit Service 6c01f9
    std::string name, email, backupFileName, expiry, serial;
Packit Service 6c01f9
    int keysize;
Packit Service 672cf4
    bool backup;
Packit Service 672cf4
};
Packit Service 672cf4
Packit Service 672cf4
GpgGenCardKeyInteractor::~GpgGenCardKeyInteractor() {}
Packit Service 672cf4
Packit Service 672cf4
GpgGenCardKeyInteractor::GpgGenCardKeyInteractor(const std::string &serial):
Packit Service 672cf4
    d(new Private)
Packit Service 672cf4
{
Packit Service 672cf4
    d->serial = serial;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
void GpgGenCardKeyInteractor::setNameUtf8(const std::string &name)
Packit Service 672cf4
{
Packit Service 672cf4
    d->name = name;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
void GpgGenCardKeyInteractor::setEmailUtf8(const std::string &email)
Packit Service 672cf4
{
Packit Service 672cf4
    d->email = email;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
void GpgGenCardKeyInteractor::setDoBackup(bool value)
Packit Service 672cf4
{
Packit Service 672cf4
    d->backup = value;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
void GpgGenCardKeyInteractor::setKeySize(int value)
Packit Service 672cf4
{
Packit Service 6c01f9
    d->keysize = value;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
void GpgGenCardKeyInteractor::setExpiry(const std::string &timeStr)
Packit Service 672cf4
{
Packit Service 672cf4
    d->expiry = timeStr;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
std::string GpgGenCardKeyInteractor::backupFileName() const
Packit Service 672cf4
{
Packit Service 672cf4
    return d->backupFileName;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
namespace GpgGenCardKeyInteractor_Private
Packit Service 672cf4
{
Packit Service 672cf4
enum {
Packit Service 672cf4
    START = EditInteractor::StartState,
Packit Service 672cf4
    DO_ADMIN,
Packit Service 672cf4
    EXPIRE,
Packit Service 672cf4
Packit Service 672cf4
    GOT_SERIAL,
Packit Service 672cf4
    COMMAND,
Packit Service 672cf4
    NAME,
Packit Service 672cf4
    EMAIL,
Packit Service 672cf4
    COMMENT,
Packit Service 672cf4
    BACKUP,
Packit Service 672cf4
    REPLACE,
Packit Service 672cf4
    SIZE,
Packit Service 672cf4
    SIZE2,
Packit Service 672cf4
    SIZE3,
Packit Service 672cf4
    BACKUP_KEY_CREATED,
Packit Service 672cf4
    KEY_CREATED,
Packit Service 672cf4
    QUIT,
Packit Service 672cf4
    SAVE,
Packit Service 672cf4
Packit Service 672cf4
    ERROR = EditInteractor::ErrorState
Packit Service 672cf4
};
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
const char *GpgGenCardKeyInteractor::action(Error &err) const
Packit Service 672cf4
{
Packit Service 672cf4
Packit Service 672cf4
    using namespace GpgGenCardKeyInteractor_Private;
Packit Service 672cf4
Packit Service 672cf4
    switch (state()) {
Packit Service 672cf4
    case DO_ADMIN:
Packit Service 672cf4
        return "admin";
Packit Service 672cf4
    case COMMAND:
Packit Service 672cf4
        return "generate";
Packit Service 672cf4
    case NAME:
Packit Service 672cf4
        return d->name.c_str();
Packit Service 672cf4
    case EMAIL:
Packit Service 672cf4
        return d->email.c_str();
Packit Service 672cf4
    case EXPIRE:
Packit Service 672cf4
        return d->expiry.c_str();
Packit Service 672cf4
    case BACKUP:
Packit Service 672cf4
        return d->backup ? "Y" : "N";
Packit Service 672cf4
    case REPLACE:
Packit Service 672cf4
        return "Y";
Packit Service 672cf4
    case SIZE:
Packit Service 672cf4
    case SIZE2:
Packit Service 672cf4
    case SIZE3:
Packit Service 6c01f9
        return std::to_string(d->keysize).c_str();
Packit Service 672cf4
    case COMMENT:
Packit Service 672cf4
        return "";
Packit Service 672cf4
    case SAVE:
Packit Service 672cf4
        return "Y";
Packit Service 672cf4
    case QUIT:
Packit Service 672cf4
        return "quit";
Packit Service 672cf4
    case KEY_CREATED:
Packit Service 672cf4
    case START:
Packit Service 672cf4
    case GOT_SERIAL:
Packit Service 672cf4
    case BACKUP_KEY_CREATED:
Packit Service 672cf4
    case ERROR:
Packit Service 6c01f9
        return 0;
Packit Service 672cf4
    default:
Packit Service 672cf4
        err = Error::fromCode(GPG_ERR_GENERAL);
Packit Service 6c01f9
        return 0;
Packit Service 672cf4
    }
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
unsigned int GpgGenCardKeyInteractor::nextState(unsigned int status, const char *args, Error &err) const
Packit Service 672cf4
{
Packit Service 672cf4
Packit Service 672cf4
    static const Error GENERAL_ERROR     = Error::fromCode(GPG_ERR_GENERAL);
Packit Service 672cf4
    static const Error INV_NAME_ERROR    = Error::fromCode(GPG_ERR_INV_NAME);
Packit Service 672cf4
    static const Error INV_EMAIL_ERROR   = Error::fromCode(GPG_ERR_INV_USER_ID);
Packit Service 672cf4
    static const Error INV_COMMENT_ERROR = Error::fromCode(GPG_ERR_INV_USER_ID);
Packit Service 672cf4
Packit Service 672cf4
    if (needsNoResponse(status)) {
Packit Service 672cf4
        return state();
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
    using namespace GpgGenCardKeyInteractor_Private;
Packit Service 672cf4
Packit Service 672cf4
    switch (state()) {
Packit Service 672cf4
    case START:
Packit Service 672cf4
        if (status == GPGME_STATUS_CARDCTRL &&
Packit Service 672cf4
                !d->serial.empty()) {
Packit Service 672cf4
            const std::string sArgs = args;
Packit Service 672cf4
            if (sArgs.find(d->serial) == std::string::npos) {
Packit Service 672cf4
                // Wrong smartcard
Packit Service 672cf4
                err = Error::fromCode(GPG_ERR_WRONG_CARD);
Packit Service 672cf4
                return ERROR;
Packit Service 672cf4
            } else {
Packit Service 672cf4
                printf("EditInteractor: Confirmed S/N: %s %s\n",
Packit Service 672cf4
                           d->serial.c_str(), sArgs.c_str());
Packit Service 672cf4
            }
Packit Service 672cf4
            return GOT_SERIAL;
Packit Service 672cf4
        } else if (d->serial.empty()) {
Packit Service 672cf4
            return GOT_SERIAL;
Packit Service 672cf4
        }
Packit Service 672cf4
        err = GENERAL_ERROR;
Packit Service 672cf4
        return ERROR;
Packit Service 672cf4
    case GOT_SERIAL:
Packit Service 672cf4
        if (status == GPGME_STATUS_GET_LINE &&
Packit Service 672cf4
                strcmp(args, "cardedit.prompt") == 0) {
Packit Service 672cf4
            return DO_ADMIN;
Packit Service 672cf4
        }
Packit Service 672cf4
        err = GENERAL_ERROR;
Packit Service 672cf4
        return ERROR;
Packit Service 672cf4
    case DO_ADMIN:
Packit Service 672cf4
        if (status == GPGME_STATUS_GET_LINE &&
Packit Service 672cf4
                strcmp(args, "cardedit.prompt") == 0) {
Packit Service 672cf4
            return COMMAND;
Packit Service 672cf4
        }
Packit Service 672cf4
        err = GENERAL_ERROR;
Packit Service 672cf4
        return ERROR;
Packit Service 672cf4
    case COMMAND:
Packit Service 672cf4
        if (status == GPGME_STATUS_GET_LINE &&
Packit Service 672cf4
                strcmp(args, "cardedit.genkeys.backup_enc") == 0) {
Packit Service 672cf4
            return BACKUP;
Packit Service 672cf4
        }
Packit Service 672cf4
        err = GENERAL_ERROR;
Packit Service 672cf4
        return ERROR;
Packit Service 672cf4
    case BACKUP:
Packit Service 672cf4
        if (status == GPGME_STATUS_GET_BOOL &&
Packit Service 672cf4
                strcmp(args, "cardedit.genkeys.replace_keys") == 0) {
Packit Service 672cf4
            return REPLACE;
Packit Service 672cf4
        }
Packit Service 672cf4
        if (status == GPGME_STATUS_GET_LINE &&
Packit Service 672cf4
                strcmp(args, "cardedit.genkeys.size") == 0) {
Packit Service 672cf4
            return SIZE;
Packit Service 672cf4
        }
Packit Service 672cf4
        err = GENERAL_ERROR;
Packit Service 672cf4
        return ERROR;
Packit Service 672cf4
    case REPLACE:
Packit Service 672cf4
        if (status == GPGME_STATUS_GET_LINE &&
Packit Service 672cf4
                strcmp(args, "cardedit.genkeys.size") == 0) {
Packit Service 6c01f9
            printf("Moving to SIZE\n");
Packit Service 672cf4
            return SIZE;
Packit Service 672cf4
        }
Packit Service 672cf4
        err = GENERAL_ERROR;
Packit Service 672cf4
        return ERROR;
Packit Service 672cf4
    case SIZE:
Packit Service 672cf4
        if (status == GPGME_STATUS_GET_LINE &&
Packit Service 672cf4
                strcmp(args, "cardedit.genkeys.size") == 0) {
Packit Service 672cf4
            return SIZE2;
Packit Service 672cf4
        }
Packit Service 672cf4
        if (status == GPGME_STATUS_GET_LINE &&
Packit Service 672cf4
                strcmp(args, "keygen.valid") == 0) {
Packit Service 672cf4
            return EXPIRE;
Packit Service 672cf4
        }
Packit Service 672cf4
        err = GENERAL_ERROR;
Packit Service 672cf4
        return ERROR;
Packit Service 672cf4
    case SIZE2:
Packit Service 672cf4
        if (status == GPGME_STATUS_GET_LINE &&
Packit Service 672cf4
                strcmp(args, "cardedit.genkeys.size") == 0) {
Packit Service 672cf4
            return SIZE3;
Packit Service 672cf4
        }
Packit Service 672cf4
        if (status == GPGME_STATUS_GET_LINE &&
Packit Service 672cf4
                strcmp(args, "keygen.valid") == 0) {
Packit Service 672cf4
            return EXPIRE;
Packit Service 672cf4
        }
Packit Service 672cf4
        err = GENERAL_ERROR;
Packit Service 672cf4
        return ERROR;
Packit Service 672cf4
    case SIZE3:
Packit Service 672cf4
        if (status == GPGME_STATUS_GET_LINE &&
Packit Service 672cf4
                strcmp(args, "keygen.valid") == 0) {
Packit Service 672cf4
            return EXPIRE;
Packit Service 672cf4
        }
Packit Service 672cf4
        err = GENERAL_ERROR;
Packit Service 672cf4
        return ERROR;
Packit Service 672cf4
    case EXPIRE:
Packit Service 672cf4
        if (status == GPGME_STATUS_GET_LINE &&
Packit Service 672cf4
                strcmp(args, "keygen.name") == 0) {
Packit Service 672cf4
            return NAME;
Packit Service 672cf4
        }
Packit Service 672cf4
        err = GENERAL_ERROR;
Packit Service 672cf4
        return ERROR;
Packit Service 672cf4
    case NAME:
Packit Service 672cf4
        if (status == GPGME_STATUS_GET_LINE &&
Packit Service 672cf4
                strcmp(args, "keygen.email") == 0) {
Packit Service 672cf4
            return EMAIL;
Packit Service 672cf4
        }
Packit Service 672cf4
        err = GENERAL_ERROR;
Packit Service 672cf4
        if (status == GPGME_STATUS_GET_LINE &&
Packit Service 672cf4
                strcmp(args, "keygen.name") == 0) {
Packit Service 672cf4
            err = INV_NAME_ERROR;
Packit Service 672cf4
        }
Packit Service 672cf4
        return ERROR;
Packit Service 672cf4
    case EMAIL:
Packit Service 672cf4
        if (status == GPGME_STATUS_GET_LINE &&
Packit Service 672cf4
                strcmp(args, "keygen.comment") == 0) {
Packit Service 672cf4
            return COMMENT;
Packit Service 672cf4
        }
Packit Service 672cf4
        err = GENERAL_ERROR;
Packit Service 672cf4
        if (status == GPGME_STATUS_GET_LINE &&
Packit Service 672cf4
                strcmp(args, "keygen.email") == 0) {
Packit Service 672cf4
            err = INV_EMAIL_ERROR;
Packit Service 672cf4
        }
Packit Service 672cf4
        return ERROR;
Packit Service 672cf4
    case COMMENT:
Packit Service 672cf4
        if (status == GPGME_STATUS_BACKUP_KEY_CREATED) {
Packit Service 672cf4
            std::string sArgs = args;
Packit Service 672cf4
            const auto pos = sArgs.rfind(" ");
Packit Service 672cf4
            if (pos != std::string::npos) {
Packit Service 672cf4
                d->backupFileName = sArgs.substr(pos + 1);
Packit Service 672cf4
                return BACKUP_KEY_CREATED;
Packit Service 672cf4
            }
Packit Service 672cf4
        }
Packit Service 672cf4
        if (status == GPGME_STATUS_KEY_CREATED) {
Packit Service 672cf4
            return KEY_CREATED;
Packit Service 672cf4
        }
Packit Service 672cf4
        if (status == GPGME_STATUS_GET_LINE &&
Packit Service 672cf4
                strcmp(args, "keyedit.prompt") == 0) {
Packit Service 672cf4
            return QUIT;
Packit Service 672cf4
        }
Packit Service 672cf4
        err = GENERAL_ERROR;
Packit Service 672cf4
        if (status == GPGME_STATUS_GET_LINE &&
Packit Service 672cf4
                strcmp(args, "keygen.comment") == 0) {
Packit Service 672cf4
            err = INV_COMMENT_ERROR;
Packit Service 672cf4
        }
Packit Service 672cf4
        return ERROR;
Packit Service 672cf4
    case BACKUP_KEY_CREATED:
Packit Service 672cf4
        if (status == GPGME_STATUS_KEY_CREATED) {
Packit Service 672cf4
            return KEY_CREATED;
Packit Service 672cf4
        }
Packit Service 672cf4
        err = GENERAL_ERROR;
Packit Service 672cf4
        return ERROR;
Packit Service 672cf4
    case KEY_CREATED:
Packit Service 672cf4
        return QUIT;
Packit Service 672cf4
    case QUIT:
Packit Service 672cf4
        if (status == GPGME_STATUS_GET_LINE &&
Packit Service 672cf4
                strcmp(args, "cardedit.prompt") == 0) {
Packit Service 672cf4
            return QUIT;
Packit Service 672cf4
        }
Packit Service 672cf4
        err = GENERAL_ERROR;
Packit Service 672cf4
        return ERROR;
Packit Service 672cf4
    case ERROR:
Packit Service 672cf4
        if (status == GPGME_STATUS_GET_LINE &&
Packit Service 672cf4
                strcmp(args, "keyedit.prompt") == 0) {
Packit Service 672cf4
            return QUIT;
Packit Service 672cf4
        }
Packit Service 672cf4
        err = lastError();
Packit Service 672cf4
        return ERROR;
Packit Service 672cf4
    default:
Packit Service 672cf4
        err = GENERAL_ERROR;
Packit Service 672cf4
        return ERROR;
Packit Service 672cf4
    }
Packit Service 672cf4
}