Blame lang/cpp/src/gpggencardkeyinteractor.cpp

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